blob: 1aa5e85e913e8cc30d7a12ca40298389ca5f7024 [file] [log] [blame]
njnc9539842002-10-02 13:26:35 +00001
njn25e49d8e72002-09-23 09:36:25 +00002/*--------------------------------------------------------------------*/
sewardj7a26f022005-11-01 17:52:34 +00003/*--- An example Valgrind tool. ---*/
njn25cac76cb2002-09-23 11:21:57 +00004/*--- lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00005/*--------------------------------------------------------------------*/
6
7/*
nethercote137bc552003-11-14 17:47:54 +00008 This file is part of Lackey, an example Valgrind tool that does
njnc9539842002-10-02 13:26:35 +00009 some simple program measurement.
njn25e49d8e72002-09-23 09:36:25 +000010
njn53612422005-03-12 16:22:54 +000011 Copyright (C) 2002-2005 Nicholas Nethercote
njn2bc10122005-05-08 02:10:27 +000012 njn@valgrind.org
njn25e49d8e72002-09-23 09:36:25 +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
29 The GNU General Public License is contained in the file COPYING.
30*/
31
njnfd73ebb2005-12-30 22:39:58 +000032// This tool shows how to do some basic instrumentation.
33//
34// In particular, if you are interested in tracing every load and store a
35// program does, use the --trace-mem=yes option. Please note that the
36// address trace is good, but not perfect; see Section 3.3.7 of Nicholas
37// Nethercote's PhD dissertation "Dynamic Binary Analysis and
38// Instrumentation", 2004, for details about the few loads and stores that
39// it misses, and other caveats about the accuracy of the address trace.
40//
41// If you want to modify how the memory traces are printed/gathered, look at
42// the code that is controlled by the variable 'lk_clo_trace_mem' and the
43// functions 'trace_load()' and 'trace_mem'.. With a bit of effort you
44// should be able to see which other bits of code can be removed, if that's
45// what you want. If you want to do more complex modifications, please read
46// VEX/pub/libvex_ir.h to understand the intermediate representation.
47//
48// For further inspiration, you should look at cachegrind/cg_main.c which
49// handles memory accesses in a more sophisticated way -- it groups them
50// together for processing into twos and threes so that fewer C calls are
51// made and things run faster.
52
njnc7561b92005-06-19 01:24:32 +000053#include "pub_tool_basics.h"
njn43b9a8a2005-05-10 04:37:01 +000054#include "pub_tool_tooliface.h"
njnf39e9a32005-06-12 02:43:17 +000055#include "pub_tool_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000056#include "pub_tool_libcprint.h"
sewardj7a26f022005-11-01 17:52:34 +000057#include "pub_tool_debuginfo.h"
58#include "pub_tool_libcbase.h"
59#include "pub_tool_options.h"
sewardj5fed8c02005-12-23 12:56:11 +000060#include "pub_tool_machine.h" // VG_(fnptr_to_fnentry)
sewardj7a26f022005-11-01 17:52:34 +000061
62/* The name of the function of which the number of calls is to be
63 * counted, with default. Override with command line option
64 * --fnname. */
65static Char* lk_clo_fnname = "_dl_runtime_resolve";
66
67/* If true, show statistics about loads, stores and alu ops. Set
68 * with command line option --detailed-counts. */
69static Bool lk_clo_detailed_counts = False;
70
njnfd73ebb2005-12-30 22:39:58 +000071/* If true, print the trace of loads and stores. Set with --trace-mem. */
72static Bool lk_clo_trace_mem = False;
73
sewardj7a26f022005-11-01 17:52:34 +000074/***********************************************************************
75 * Implement the needs_command_line_options for Valgrind.
76 **********************************************************************/
77
78static Bool lk_process_cmd_line_option(Char* arg)
79{
80 VG_STR_CLO(arg, "--fnname", lk_clo_fnname)
81 else VG_BOOL_CLO(arg, "--detailed-counts", lk_clo_detailed_counts)
njnfd73ebb2005-12-30 22:39:58 +000082 else VG_BOOL_CLO(arg, "--trace-mem", lk_clo_trace_mem)
sewardj7a26f022005-11-01 17:52:34 +000083 else
84 return False;
85
86 tl_assert(lk_clo_fnname);
87 tl_assert(lk_clo_fnname[0]);
88 return True;
89}
90
91static void lk_print_usage(void)
92{
93 VG_(printf)(
94" --fnname=<name> count calls to <name> [_dl_runtime_resolve]\n"
95" --detailed-counts=no|yes count loads, stores and alu ops [no]\n"
96 );
97}
98
99static void lk_print_debug_usage(void)
100{
101}
102
103/***********************************************************************
104 * Data and helpers related to the default operation of Lackey.
105 **********************************************************************/
njn25e49d8e72002-09-23 09:36:25 +0000106
njn25e49d8e72002-09-23 09:36:25 +0000107/* Nb: use ULongs because the numbers can get very big */
sewardj7a26f022005-11-01 17:52:34 +0000108static ULong n_func_calls = 0;
109static ULong n_BBs_entered = 0;
110static ULong n_BBs_completed = 0;
111static ULong n_IRStmts = 0;
112static ULong n_guest_instrs = 0;
113static ULong n_Jccs = 0;
114static ULong n_Jccs_untaken = 0;
njn25e49d8e72002-09-23 09:36:25 +0000115
sewardj7a26f022005-11-01 17:52:34 +0000116static void add_one_func_call(void)
njn25e49d8e72002-09-23 09:36:25 +0000117{
sewardj7a26f022005-11-01 17:52:34 +0000118 n_func_calls++;
njn25e49d8e72002-09-23 09:36:25 +0000119}
120
sewardj7a26f022005-11-01 17:52:34 +0000121static void add_one_BB_entered(void)
njn25e49d8e72002-09-23 09:36:25 +0000122{
sewardj7a26f022005-11-01 17:52:34 +0000123 n_BBs_entered++;
124}
125
126static void add_one_BB_completed(void)
127{
128 n_BBs_completed++;
njn25e49d8e72002-09-23 09:36:25 +0000129}
130
sewardj7a26f022005-11-01 17:52:34 +0000131static void add_one_IRStmt(void)
njn25e49d8e72002-09-23 09:36:25 +0000132{
sewardj7a26f022005-11-01 17:52:34 +0000133 n_IRStmts++;
njn25e49d8e72002-09-23 09:36:25 +0000134}
135
sewardj9f649aa2004-11-22 20:38:40 +0000136static void add_one_guest_instr(void)
njn25e49d8e72002-09-23 09:36:25 +0000137{
sewardj9f649aa2004-11-22 20:38:40 +0000138 n_guest_instrs++;
njn25e49d8e72002-09-23 09:36:25 +0000139}
140
141static void add_one_Jcc(void)
142{
143 n_Jccs++;
144}
145
146static void add_one_Jcc_untaken(void)
147{
148 n_Jccs_untaken++;
149}
150
sewardj7a26f022005-11-01 17:52:34 +0000151/***********************************************************************
152 * Data and helpers related to --detailed-counts.
153 **********************************************************************/
154
155/* --- Operations --- */
156
157typedef enum { OpLoad=0, OpStore=1, OpAlu=2 } Op;
158
159#define N_OPS 3
160
161
162/* --- Types --- */
163
164#define N_TYPES 9
165
166static Int type2index ( IRType ty )
njn25e49d8e72002-09-23 09:36:25 +0000167{
sewardj7a26f022005-11-01 17:52:34 +0000168 switch (ty) {
169 case Ity_I1: return 0;
170 case Ity_I8: return 1;
171 case Ity_I16: return 2;
172 case Ity_I32: return 3;
173 case Ity_I64: return 4;
174 case Ity_I128: return 5;
175 case Ity_F32: return 6;
176 case Ity_F64: return 7;
177 case Ity_V128: return 8;
178 default: tl_assert(0); break;
179 }
njn25e49d8e72002-09-23 09:36:25 +0000180}
181
sewardj7a26f022005-11-01 17:52:34 +0000182static HChar* nameOfTypeIndex ( IRType ty )
183{
184 switch (ty) {
185 case 0: return "I1"; break;
186 case 1: return "I8"; break;
187 case 2: return "I16"; break;
188 case 3: return "I32"; break;
189 case 4: return "I64"; break;
190 case 5: return "I128"; break;
191 case 6: return "F32"; break;
192 case 7: return "F64"; break;
193 case 8: return "V128"; break;
194 default: tl_assert(0); break;
195 }
196}
njn25e49d8e72002-09-23 09:36:25 +0000197
njn25e49d8e72002-09-23 09:36:25 +0000198
sewardj7a26f022005-11-01 17:52:34 +0000199/* --- Counts --- */
njn25e49d8e72002-09-23 09:36:25 +0000200
sewardj7a26f022005-11-01 17:52:34 +0000201static ULong detailCounts[N_OPS][N_TYPES];
njn25e49d8e72002-09-23 09:36:25 +0000202
sewardj7a26f022005-11-01 17:52:34 +0000203/* The helper that is called from the instrumented code. */
204static VG_REGPARM(1)
205void increment_detail(ULong* detail)
206{
207 (*detail)++;
208}
njn25e49d8e72002-09-23 09:36:25 +0000209
sewardj7a26f022005-11-01 17:52:34 +0000210/* A helper that adds the instrumentation for a detail. */
211static void instrument_detail(IRBB* bb, Op op, IRType type)
212{
213 IRDirty* di;
214 IRExpr** argv;
215 const UInt typeIx = type2index(type);
njn25e49d8e72002-09-23 09:36:25 +0000216
sewardj7a26f022005-11-01 17:52:34 +0000217 tl_assert(op < N_OPS);
218 tl_assert(typeIx < N_TYPES);
njn25e49d8e72002-09-23 09:36:25 +0000219
sewardj7a26f022005-11-01 17:52:34 +0000220 argv = mkIRExprVec_1( mkIRExpr_HWord( (HWord)&detailCounts[op][typeIx] ) );
sewardj5fed8c02005-12-23 12:56:11 +0000221 di = unsafeIRDirty_0_N( 1, "increment_detail",
222 VG_(fnptr_to_fnentry)( &increment_detail ),
223 argv);
sewardj7a26f022005-11-01 17:52:34 +0000224 addStmtToIRBB( bb, IRStmt_Dirty(di) );
225}
njn25e49d8e72002-09-23 09:36:25 +0000226
sewardj7a26f022005-11-01 17:52:34 +0000227/* Summarize and print the details. */
njn25e49d8e72002-09-23 09:36:25 +0000228
sewardj7a26f022005-11-01 17:52:34 +0000229static void print_details ( void )
230{
231 Int typeIx;
232 VG_(message)(Vg_UserMsg,
233 " Type Loads Stores AluOps");
234 VG_(message)(Vg_UserMsg,
235 " -------------------------------------------");
236 for (typeIx = 0; typeIx < N_TYPES; typeIx++) {
237 VG_(message)(Vg_UserMsg,
238 " %4s %,12llu %,12llu %,12llu",
239 nameOfTypeIndex( typeIx ),
240 detailCounts[OpLoad ][typeIx],
241 detailCounts[OpStore][typeIx],
242 detailCounts[OpAlu ][typeIx]
243 );
244 }
245}
njn25e49d8e72002-09-23 09:36:25 +0000246
sewardj7a26f022005-11-01 17:52:34 +0000247
248/***********************************************************************
njnfd73ebb2005-12-30 22:39:58 +0000249 * Data and helpers related to --trace-mem.
250 **********************************************************************/
251
252static VG_REGPARM(2) void trace_load(Addr addr, SizeT size)
253{
254 VG_(printf)("load : %p, %d\n", addr, size);
255}
256
257static VG_REGPARM(2) void trace_store(Addr addr, SizeT size)
258{
259 VG_(printf)("store: %p, %d\n", addr, size);
260}
261
262/***********************************************************************
sewardj7a26f022005-11-01 17:52:34 +0000263 * Implement the basic_tool_funcs for Valgrind.
264 **********************************************************************/
265
266static void lk_post_clo_init(void)
267{
268 Int op, tyIx;
269
270 for (op = 0; op < N_OPS; op++)
271 for (tyIx = 0; tyIx < N_TYPES; tyIx++)
272 detailCounts[op][tyIx] = 0;
273}
274
sewardj4ba057c2005-10-18 12:04:18 +0000275static
276IRBB* lk_instrument( IRBB* bb_in, VexGuestLayout* layout,
277 Addr64 orig_addr_noredir, VexGuestExtents* vge,
278 IRType gWordTy, IRType hWordTy )
njn25e49d8e72002-09-23 09:36:25 +0000279{
sewardj9f649aa2004-11-22 20:38:40 +0000280 IRDirty* di;
281 Int i;
sewardjd54babf2005-03-21 00:55:49 +0000282 IRBB* bb;
sewardj7a26f022005-11-01 17:52:34 +0000283 Char fnname[100];
284 IRType type;
njnfd73ebb2005-12-30 22:39:58 +0000285 IRExpr** argv;
286 IRExpr* addr_expr;
287 IRExpr* size_expr;
sewardjd54babf2005-03-21 00:55:49 +0000288
289 if (gWordTy != hWordTy) {
290 /* We don't currently support this case. */
291 VG_(tool_panic)("host/guest word size mismatch");
292 }
sewardj9f649aa2004-11-22 20:38:40 +0000293
294 /* Set up BB */
sewardjd54babf2005-03-21 00:55:49 +0000295 bb = emptyIRBB();
sewardj9f649aa2004-11-22 20:38:40 +0000296 bb->tyenv = dopyIRTypeEnv(bb_in->tyenv);
297 bb->next = dopyIRExpr(bb_in->next);
298 bb->jumpkind = bb_in->jumpkind;
299
sewardj7a26f022005-11-01 17:52:34 +0000300 // Copy verbatim any IR preamble preceding the first IMark
301 i = 0;
302 while (i < bb_in->stmts_used && bb_in->stmts[i]->tag != Ist_IMark) {
303 addStmtToIRBB( bb, bb_in->stmts[i] );
304 i++;
sewardj9f649aa2004-11-22 20:38:40 +0000305 }
sewardj9f649aa2004-11-22 20:38:40 +0000306
sewardj7a26f022005-11-01 17:52:34 +0000307 /* Count this basic block. */
sewardj5fed8c02005-12-23 12:56:11 +0000308 di = unsafeIRDirty_0_N( 0, "add_one_BB_entered",
309 VG_(fnptr_to_fnentry)( &add_one_BB_entered ),
sewardj7a26f022005-11-01 17:52:34 +0000310 mkIRExprVec_0() );
sewardj9f649aa2004-11-22 20:38:40 +0000311 addStmtToIRBB( bb, IRStmt_Dirty(di) );
312
sewardj7a26f022005-11-01 17:52:34 +0000313 for (/*use current i*/; i < bb_in->stmts_used; i++) {
sewardj9f649aa2004-11-22 20:38:40 +0000314 IRStmt* st = bb_in->stmts[i];
sewardj7a26f022005-11-01 17:52:34 +0000315 if (!st || st->tag == Ist_NoOp) continue;
sewardj9f649aa2004-11-22 20:38:40 +0000316
sewardj7a26f022005-11-01 17:52:34 +0000317 /* Count one VEX statement. */
sewardj5fed8c02005-12-23 12:56:11 +0000318 di = unsafeIRDirty_0_N( 0, "add_one_IRStmt",
319 VG_(fnptr_to_fnentry)( &add_one_IRStmt ),
sewardj7a26f022005-11-01 17:52:34 +0000320 mkIRExprVec_0() );
321 addStmtToIRBB( bb, IRStmt_Dirty(di) );
322
sewardj9f649aa2004-11-22 20:38:40 +0000323 switch (st->tag) {
sewardj7a26f022005-11-01 17:52:34 +0000324 case Ist_IMark:
325 /* Count guest instruction. */
326 di = unsafeIRDirty_0_N( 0, "add_one_guest_instr",
sewardj5fed8c02005-12-23 12:56:11 +0000327 VG_(fnptr_to_fnentry)( &add_one_guest_instr ),
sewardj7a26f022005-11-01 17:52:34 +0000328 mkIRExprVec_0() );
329 addStmtToIRBB( bb, IRStmt_Dirty(di) );
330
331 /* An unconditional branch to a known destination in the
332 * guest's instructions can be represented, in the IRBB to
333 * instrument, by the VEX statements that are the
334 * translation of that known destination. This feature is
335 * called 'BB chasing' and can be influenced by command
336 * line option --vex-guest-chase-thresh.
337 *
338 * To get an accurate count of the calls to a specific
339 * function, taking BB chasing into account, we need to
340 * check for each guest instruction (Ist_IMark) if it is
341 * the entry point of a function.
342 */
343 tl_assert(lk_clo_fnname);
344 tl_assert(lk_clo_fnname[0]);
345 if (VG_(get_fnname_if_entry)(st->Ist.IMark.addr,
346 fnname, sizeof(fnname))
347 && 0 == VG_(strcmp)(fnname, lk_clo_fnname)) {
sewardj5fed8c02005-12-23 12:56:11 +0000348 di = unsafeIRDirty_0_N(
349 0, "add_one_func_call",
350 VG_(fnptr_to_fnentry)( &add_one_func_call ),
351 mkIRExprVec_0() );
sewardj7a26f022005-11-01 17:52:34 +0000352 addStmtToIRBB( bb, IRStmt_Dirty(di) );
353 }
354 addStmtToIRBB( bb, st );
355 break;
356
sewardj9f649aa2004-11-22 20:38:40 +0000357 case Ist_Exit:
358 /* Count Jcc */
sewardj5fed8c02005-12-23 12:56:11 +0000359 di = unsafeIRDirty_0_N( 0, "add_one_Jcc",
360 VG_(fnptr_to_fnentry)( &add_one_Jcc ),
sewardj7a26f022005-11-01 17:52:34 +0000361 mkIRExprVec_0() );
362 addStmtToIRBB( bb, IRStmt_Dirty(di) );
363
364 addStmtToIRBB( bb, st );
365
sewardj9f649aa2004-11-22 20:38:40 +0000366 /* Count non-taken Jcc */
sewardj7a26f022005-11-01 17:52:34 +0000367 di = unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken",
sewardj5fed8c02005-12-23 12:56:11 +0000368 VG_(fnptr_to_fnentry)( &add_one_Jcc_untaken ),
369 mkIRExprVec_0() );
sewardj7a26f022005-11-01 17:52:34 +0000370 addStmtToIRBB( bb, IRStmt_Dirty(di) );
371 break;
372
373 /* Someone on the users list asked for something like this
374 * just the other day (Christian Stimming, "Fast profiling in
375 * valgrind?", 25 Oct). Personally I think it'd be a
376 * valuable addition.
377 *
378 * Not hard to do either: for stores, examine Ist_Store, and
379 * use typeOfIRExpr(bb->tyenv, st->Ist.Store.data) to get the
380 * store type. For loads and ALU ops, you only need to look
381 * at Ist_Tmp cases where the Ist.Tmp.data is either Iex_Load
382 * or Iex_{Unop,Binop}. All statements you will ever
383 * encounter will satisfy isFlatIRStmt which essentially
384 * constrains them to being flat SSA-style.
385 */
386 case Ist_Store:
njnfd73ebb2005-12-30 22:39:58 +0000387 // Add a call to trace_store() if --trace-mem=yes.
388 if (lk_clo_trace_mem) {
389 addr_expr = st->Ist.Store.addr;
390 size_expr = mkIRExpr_HWord(
391 sizeofIRType(
392 typeOfIRExpr(bb->tyenv, st->Ist.Store.data)));
393 argv = mkIRExprVec_2( addr_expr, size_expr );
394 di = unsafeIRDirty_0_N( /*regparms*/2,
395 "trace_store",
396 VG_(fnptr_to_fnentry)( trace_store ),
397 argv );
398 addStmtToIRBB( bb, IRStmt_Dirty(di) );
399 }
sewardj7a26f022005-11-01 17:52:34 +0000400 if (lk_clo_detailed_counts) {
401 type = typeOfIRExpr(bb->tyenv, st->Ist.Store.data);
402 tl_assert(type != Ity_INVALID);
403 instrument_detail( bb, OpStore, type );
404 }
405 addStmtToIRBB( bb, st );
406 break;
407
408 case Ist_Tmp:
njnfd73ebb2005-12-30 22:39:58 +0000409 // Add a call to trace_load() if --trace-mem=yes.
410 if (lk_clo_trace_mem) {
411 IRExpr* data = st->Ist.Tmp.data;
412 if (data->tag == Iex_Load) {
413 addr_expr = data->Iex.Load.addr;
414 size_expr = mkIRExpr_HWord( sizeofIRType(data->Iex.Load.ty) );
415 argv = mkIRExprVec_2( addr_expr, size_expr );
416 di = unsafeIRDirty_0_N( /*regparms*/2,
417 "trace_load",
418 VG_(fnptr_to_fnentry)( trace_load ),
419 argv );
420 addStmtToIRBB( bb, IRStmt_Dirty(di) );
421 }
422 }
sewardj7a26f022005-11-01 17:52:34 +0000423 if (lk_clo_detailed_counts) {
424 IRExpr* expr = st->Ist.Tmp.data;
425 type = typeOfIRExpr(bb->tyenv, expr);
426 tl_assert(type != Ity_INVALID);
427 switch (expr->tag) {
428 case Iex_Load:
429 instrument_detail( bb, OpLoad, type );
430 break;
431 case Iex_Unop:
432 case Iex_Binop:
433 case Iex_Mux0X:
434 instrument_detail( bb, OpAlu, type );
435 break;
436 default:
437 break;
438 }
439 }
440 addStmtToIRBB( bb, st );
sewardj9f649aa2004-11-22 20:38:40 +0000441 break;
442
443 default:
sewardjbd598e12005-01-07 12:10:21 +0000444 addStmtToIRBB( bb, st );
sewardj9f649aa2004-11-22 20:38:40 +0000445 }
446 }
447
sewardj7a26f022005-11-01 17:52:34 +0000448 /* Count this basic block. */
449 di = unsafeIRDirty_0_N( 0, "add_one_BB_completed",
sewardj5fed8c02005-12-23 12:56:11 +0000450 VG_(fnptr_to_fnentry)( &add_one_BB_completed ),
451 mkIRExprVec_0() );
sewardj7a26f022005-11-01 17:52:34 +0000452 addStmtToIRBB( bb, IRStmt_Dirty(di) );
453
sewardj9f649aa2004-11-22 20:38:40 +0000454 return bb;
njn25e49d8e72002-09-23 09:36:25 +0000455}
456
njn51d827b2005-05-09 01:02:08 +0000457static void lk_fini(Int exitcode)
njn25e49d8e72002-09-23 09:36:25 +0000458{
sewardj7a26f022005-11-01 17:52:34 +0000459 char percentify_buf[4]; /* Two digits, '%' and 0. */
460 const int percentify_size = sizeof(percentify_buf);
461 const int percentify_decs = 0;
462
463 tl_assert(lk_clo_fnname);
464 tl_assert(lk_clo_fnname[0]);
465 VG_(message)(Vg_UserMsg,
466 "Counted %,llu calls to %s()", n_func_calls, lk_clo_fnname);
njn25e49d8e72002-09-23 09:36:25 +0000467
sewardj7a26f022005-11-01 17:52:34 +0000468 VG_(message)(Vg_UserMsg, "");
469 VG_(message)(Vg_UserMsg, "Jccs:");
470 VG_(message)(Vg_UserMsg, " total: %,llu", n_Jccs);
471 VG_(percentify)((n_Jccs - n_Jccs_untaken), (n_Jccs ? n_Jccs : 1),
472 percentify_decs, percentify_size, percentify_buf);
473 VG_(message)(Vg_UserMsg, " taken: %,llu (%s)",
474 (n_Jccs - n_Jccs_untaken), percentify_buf);
475
476 VG_(message)(Vg_UserMsg, "");
477 VG_(message)(Vg_UserMsg, "Executed:");
478 VG_(message)(Vg_UserMsg, " BBs entered: %,llu", n_BBs_entered);
479 VG_(message)(Vg_UserMsg, " BBs completed: %,llu", n_BBs_completed);
480 VG_(message)(Vg_UserMsg, " guest instrs: %,llu", n_guest_instrs);
481 VG_(message)(Vg_UserMsg, " IRStmts: %,llu", n_IRStmts);
482
483 VG_(message)(Vg_UserMsg, "");
484 VG_(message)(Vg_UserMsg, "Ratios:");
485 tl_assert(n_BBs_entered); // Paranoia time.
486 VG_(message)(Vg_UserMsg, " guest instrs : BB entered = %3u : 10",
487 10 * n_guest_instrs / n_BBs_entered);
488 VG_(message)(Vg_UserMsg, " IRStmts : BB entered = %3u : 10",
489 10 * n_IRStmts / n_BBs_entered);
490 tl_assert(n_guest_instrs); // Paranoia time.
491 VG_(message)(Vg_UserMsg, " IRStmts : guest instr = %3u : 10",
492 10 * n_IRStmts / n_guest_instrs);
njn25e49d8e72002-09-23 09:36:25 +0000493
sewardj7a26f022005-11-01 17:52:34 +0000494 if (lk_clo_detailed_counts) {
495 VG_(message)(Vg_UserMsg, "");
496 VG_(message)(Vg_UserMsg, "IR-level counts by type:");
497 print_details();
498 }
njn25e49d8e72002-09-23 09:36:25 +0000499
sewardj7a26f022005-11-01 17:52:34 +0000500 VG_(message)(Vg_UserMsg, "");
501 VG_(message)(Vg_UserMsg, "Exit code: %d", exitcode);
njn25e49d8e72002-09-23 09:36:25 +0000502}
503
njn51d827b2005-05-09 01:02:08 +0000504static void lk_pre_clo_init(void)
505{
506 VG_(details_name) ("Lackey");
507 VG_(details_version) (NULL);
508 VG_(details_description) ("an example Valgrind tool");
509 VG_(details_copyright_author)(
510 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote.");
511 VG_(details_bug_reports_to) (VG_BUGS_TO);
512 VG_(details_avg_translation_sizeB) ( 175 );
513
514 VG_(basic_tool_funcs) (lk_post_clo_init,
515 lk_instrument,
516 lk_fini);
sewardj7a26f022005-11-01 17:52:34 +0000517 VG_(needs_command_line_options)(lk_process_cmd_line_option,
518 lk_print_usage,
519 lk_print_debug_usage);
njn51d827b2005-05-09 01:02:08 +0000520}
521
sewardj45f4e7c2005-09-27 19:20:21 +0000522VG_DETERMINE_INTERFACE_VERSION(lk_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +0000523
njn25e49d8e72002-09-23 09:36:25 +0000524/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000525/*--- end lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +0000526/*--------------------------------------------------------------------*/