blob: d5a02224bf1e2d11ce41406ce8068b9688ebefa5 [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
sewardj461df9c2006-01-17 02:06:39 +0000276IRBB* lk_instrument ( VgCallbackClosure* closure,
277 IRBB* bb_in,
278 VexGuestLayout* layout,
279 VexGuestExtents* vge,
280 IRType gWordTy, IRType hWordTy )
njn25e49d8e72002-09-23 09:36:25 +0000281{
sewardj9f649aa2004-11-22 20:38:40 +0000282 IRDirty* di;
283 Int i;
sewardjd54babf2005-03-21 00:55:49 +0000284 IRBB* bb;
sewardj7a26f022005-11-01 17:52:34 +0000285 Char fnname[100];
286 IRType type;
njnfd73ebb2005-12-30 22:39:58 +0000287 IRExpr** argv;
288 IRExpr* addr_expr;
289 IRExpr* size_expr;
sewardjd54babf2005-03-21 00:55:49 +0000290
291 if (gWordTy != hWordTy) {
292 /* We don't currently support this case. */
293 VG_(tool_panic)("host/guest word size mismatch");
294 }
sewardj9f649aa2004-11-22 20:38:40 +0000295
296 /* Set up BB */
sewardjd54babf2005-03-21 00:55:49 +0000297 bb = emptyIRBB();
sewardj9f649aa2004-11-22 20:38:40 +0000298 bb->tyenv = dopyIRTypeEnv(bb_in->tyenv);
299 bb->next = dopyIRExpr(bb_in->next);
300 bb->jumpkind = bb_in->jumpkind;
301
sewardj7a26f022005-11-01 17:52:34 +0000302 // Copy verbatim any IR preamble preceding the first IMark
303 i = 0;
304 while (i < bb_in->stmts_used && bb_in->stmts[i]->tag != Ist_IMark) {
305 addStmtToIRBB( bb, bb_in->stmts[i] );
306 i++;
sewardj9f649aa2004-11-22 20:38:40 +0000307 }
sewardj9f649aa2004-11-22 20:38:40 +0000308
sewardj7a26f022005-11-01 17:52:34 +0000309 /* Count this basic block. */
sewardj5fed8c02005-12-23 12:56:11 +0000310 di = unsafeIRDirty_0_N( 0, "add_one_BB_entered",
311 VG_(fnptr_to_fnentry)( &add_one_BB_entered ),
sewardj7a26f022005-11-01 17:52:34 +0000312 mkIRExprVec_0() );
sewardj9f649aa2004-11-22 20:38:40 +0000313 addStmtToIRBB( bb, IRStmt_Dirty(di) );
314
sewardj7a26f022005-11-01 17:52:34 +0000315 for (/*use current i*/; i < bb_in->stmts_used; i++) {
sewardj9f649aa2004-11-22 20:38:40 +0000316 IRStmt* st = bb_in->stmts[i];
sewardj7a26f022005-11-01 17:52:34 +0000317 if (!st || st->tag == Ist_NoOp) continue;
sewardj9f649aa2004-11-22 20:38:40 +0000318
sewardj7a26f022005-11-01 17:52:34 +0000319 /* Count one VEX statement. */
sewardj5fed8c02005-12-23 12:56:11 +0000320 di = unsafeIRDirty_0_N( 0, "add_one_IRStmt",
321 VG_(fnptr_to_fnentry)( &add_one_IRStmt ),
sewardj7a26f022005-11-01 17:52:34 +0000322 mkIRExprVec_0() );
323 addStmtToIRBB( bb, IRStmt_Dirty(di) );
324
sewardj9f649aa2004-11-22 20:38:40 +0000325 switch (st->tag) {
sewardj7a26f022005-11-01 17:52:34 +0000326 case Ist_IMark:
327 /* Count guest instruction. */
328 di = unsafeIRDirty_0_N( 0, "add_one_guest_instr",
sewardj5fed8c02005-12-23 12:56:11 +0000329 VG_(fnptr_to_fnentry)( &add_one_guest_instr ),
sewardj7a26f022005-11-01 17:52:34 +0000330 mkIRExprVec_0() );
331 addStmtToIRBB( bb, IRStmt_Dirty(di) );
332
333 /* An unconditional branch to a known destination in the
334 * guest's instructions can be represented, in the IRBB to
335 * instrument, by the VEX statements that are the
336 * translation of that known destination. This feature is
337 * called 'BB chasing' and can be influenced by command
338 * line option --vex-guest-chase-thresh.
339 *
340 * To get an accurate count of the calls to a specific
341 * function, taking BB chasing into account, we need to
342 * check for each guest instruction (Ist_IMark) if it is
343 * the entry point of a function.
344 */
345 tl_assert(lk_clo_fnname);
346 tl_assert(lk_clo_fnname[0]);
347 if (VG_(get_fnname_if_entry)(st->Ist.IMark.addr,
348 fnname, sizeof(fnname))
349 && 0 == VG_(strcmp)(fnname, lk_clo_fnname)) {
sewardj5fed8c02005-12-23 12:56:11 +0000350 di = unsafeIRDirty_0_N(
351 0, "add_one_func_call",
352 VG_(fnptr_to_fnentry)( &add_one_func_call ),
353 mkIRExprVec_0() );
sewardj7a26f022005-11-01 17:52:34 +0000354 addStmtToIRBB( bb, IRStmt_Dirty(di) );
355 }
356 addStmtToIRBB( bb, st );
357 break;
358
sewardj9f649aa2004-11-22 20:38:40 +0000359 case Ist_Exit:
360 /* Count Jcc */
sewardj5fed8c02005-12-23 12:56:11 +0000361 di = unsafeIRDirty_0_N( 0, "add_one_Jcc",
362 VG_(fnptr_to_fnentry)( &add_one_Jcc ),
sewardj7a26f022005-11-01 17:52:34 +0000363 mkIRExprVec_0() );
364 addStmtToIRBB( bb, IRStmt_Dirty(di) );
365
366 addStmtToIRBB( bb, st );
367
sewardj9f649aa2004-11-22 20:38:40 +0000368 /* Count non-taken Jcc */
sewardj7a26f022005-11-01 17:52:34 +0000369 di = unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken",
sewardj5fed8c02005-12-23 12:56:11 +0000370 VG_(fnptr_to_fnentry)( &add_one_Jcc_untaken ),
371 mkIRExprVec_0() );
sewardj7a26f022005-11-01 17:52:34 +0000372 addStmtToIRBB( bb, IRStmt_Dirty(di) );
373 break;
374
375 /* Someone on the users list asked for something like this
376 * just the other day (Christian Stimming, "Fast profiling in
377 * valgrind?", 25 Oct). Personally I think it'd be a
378 * valuable addition.
379 *
380 * Not hard to do either: for stores, examine Ist_Store, and
381 * use typeOfIRExpr(bb->tyenv, st->Ist.Store.data) to get the
382 * store type. For loads and ALU ops, you only need to look
383 * at Ist_Tmp cases where the Ist.Tmp.data is either Iex_Load
384 * or Iex_{Unop,Binop}. All statements you will ever
385 * encounter will satisfy isFlatIRStmt which essentially
386 * constrains them to being flat SSA-style.
387 */
388 case Ist_Store:
njnfd73ebb2005-12-30 22:39:58 +0000389 // Add a call to trace_store() if --trace-mem=yes.
390 if (lk_clo_trace_mem) {
391 addr_expr = st->Ist.Store.addr;
392 size_expr = mkIRExpr_HWord(
393 sizeofIRType(
394 typeOfIRExpr(bb->tyenv, st->Ist.Store.data)));
395 argv = mkIRExprVec_2( addr_expr, size_expr );
396 di = unsafeIRDirty_0_N( /*regparms*/2,
397 "trace_store",
398 VG_(fnptr_to_fnentry)( trace_store ),
399 argv );
400 addStmtToIRBB( bb, IRStmt_Dirty(di) );
401 }
sewardj7a26f022005-11-01 17:52:34 +0000402 if (lk_clo_detailed_counts) {
403 type = typeOfIRExpr(bb->tyenv, st->Ist.Store.data);
404 tl_assert(type != Ity_INVALID);
405 instrument_detail( bb, OpStore, type );
406 }
407 addStmtToIRBB( bb, st );
408 break;
409
410 case Ist_Tmp:
njnfd73ebb2005-12-30 22:39:58 +0000411 // Add a call to trace_load() if --trace-mem=yes.
412 if (lk_clo_trace_mem) {
413 IRExpr* data = st->Ist.Tmp.data;
414 if (data->tag == Iex_Load) {
415 addr_expr = data->Iex.Load.addr;
416 size_expr = mkIRExpr_HWord( sizeofIRType(data->Iex.Load.ty) );
417 argv = mkIRExprVec_2( addr_expr, size_expr );
418 di = unsafeIRDirty_0_N( /*regparms*/2,
419 "trace_load",
420 VG_(fnptr_to_fnentry)( trace_load ),
421 argv );
422 addStmtToIRBB( bb, IRStmt_Dirty(di) );
423 }
424 }
sewardj7a26f022005-11-01 17:52:34 +0000425 if (lk_clo_detailed_counts) {
426 IRExpr* expr = st->Ist.Tmp.data;
427 type = typeOfIRExpr(bb->tyenv, expr);
428 tl_assert(type != Ity_INVALID);
429 switch (expr->tag) {
430 case Iex_Load:
431 instrument_detail( bb, OpLoad, type );
432 break;
433 case Iex_Unop:
434 case Iex_Binop:
435 case Iex_Mux0X:
436 instrument_detail( bb, OpAlu, type );
437 break;
438 default:
439 break;
440 }
441 }
442 addStmtToIRBB( bb, st );
sewardj9f649aa2004-11-22 20:38:40 +0000443 break;
444
445 default:
sewardjbd598e12005-01-07 12:10:21 +0000446 addStmtToIRBB( bb, st );
sewardj9f649aa2004-11-22 20:38:40 +0000447 }
448 }
449
sewardj7a26f022005-11-01 17:52:34 +0000450 /* Count this basic block. */
451 di = unsafeIRDirty_0_N( 0, "add_one_BB_completed",
sewardj5fed8c02005-12-23 12:56:11 +0000452 VG_(fnptr_to_fnentry)( &add_one_BB_completed ),
453 mkIRExprVec_0() );
sewardj7a26f022005-11-01 17:52:34 +0000454 addStmtToIRBB( bb, IRStmt_Dirty(di) );
455
sewardj9f649aa2004-11-22 20:38:40 +0000456 return bb;
njn25e49d8e72002-09-23 09:36:25 +0000457}
458
njn51d827b2005-05-09 01:02:08 +0000459static void lk_fini(Int exitcode)
njn25e49d8e72002-09-23 09:36:25 +0000460{
sewardj7a26f022005-11-01 17:52:34 +0000461 char percentify_buf[4]; /* Two digits, '%' and 0. */
462 const int percentify_size = sizeof(percentify_buf);
463 const int percentify_decs = 0;
464
465 tl_assert(lk_clo_fnname);
466 tl_assert(lk_clo_fnname[0]);
467 VG_(message)(Vg_UserMsg,
468 "Counted %,llu calls to %s()", n_func_calls, lk_clo_fnname);
njn25e49d8e72002-09-23 09:36:25 +0000469
sewardj7a26f022005-11-01 17:52:34 +0000470 VG_(message)(Vg_UserMsg, "");
471 VG_(message)(Vg_UserMsg, "Jccs:");
472 VG_(message)(Vg_UserMsg, " total: %,llu", n_Jccs);
473 VG_(percentify)((n_Jccs - n_Jccs_untaken), (n_Jccs ? n_Jccs : 1),
474 percentify_decs, percentify_size, percentify_buf);
475 VG_(message)(Vg_UserMsg, " taken: %,llu (%s)",
476 (n_Jccs - n_Jccs_untaken), percentify_buf);
477
478 VG_(message)(Vg_UserMsg, "");
479 VG_(message)(Vg_UserMsg, "Executed:");
480 VG_(message)(Vg_UserMsg, " BBs entered: %,llu", n_BBs_entered);
481 VG_(message)(Vg_UserMsg, " BBs completed: %,llu", n_BBs_completed);
482 VG_(message)(Vg_UserMsg, " guest instrs: %,llu", n_guest_instrs);
483 VG_(message)(Vg_UserMsg, " IRStmts: %,llu", n_IRStmts);
484
485 VG_(message)(Vg_UserMsg, "");
486 VG_(message)(Vg_UserMsg, "Ratios:");
487 tl_assert(n_BBs_entered); // Paranoia time.
488 VG_(message)(Vg_UserMsg, " guest instrs : BB entered = %3u : 10",
489 10 * n_guest_instrs / n_BBs_entered);
490 VG_(message)(Vg_UserMsg, " IRStmts : BB entered = %3u : 10",
491 10 * n_IRStmts / n_BBs_entered);
492 tl_assert(n_guest_instrs); // Paranoia time.
493 VG_(message)(Vg_UserMsg, " IRStmts : guest instr = %3u : 10",
494 10 * n_IRStmts / n_guest_instrs);
njn25e49d8e72002-09-23 09:36:25 +0000495
sewardj7a26f022005-11-01 17:52:34 +0000496 if (lk_clo_detailed_counts) {
497 VG_(message)(Vg_UserMsg, "");
498 VG_(message)(Vg_UserMsg, "IR-level counts by type:");
499 print_details();
500 }
njn25e49d8e72002-09-23 09:36:25 +0000501
sewardj7a26f022005-11-01 17:52:34 +0000502 VG_(message)(Vg_UserMsg, "");
503 VG_(message)(Vg_UserMsg, "Exit code: %d", exitcode);
njn25e49d8e72002-09-23 09:36:25 +0000504}
505
njn51d827b2005-05-09 01:02:08 +0000506static void lk_pre_clo_init(void)
507{
508 VG_(details_name) ("Lackey");
509 VG_(details_version) (NULL);
510 VG_(details_description) ("an example Valgrind tool");
511 VG_(details_copyright_author)(
512 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote.");
513 VG_(details_bug_reports_to) (VG_BUGS_TO);
514 VG_(details_avg_translation_sizeB) ( 175 );
515
516 VG_(basic_tool_funcs) (lk_post_clo_init,
517 lk_instrument,
518 lk_fini);
sewardj7a26f022005-11-01 17:52:34 +0000519 VG_(needs_command_line_options)(lk_process_cmd_line_option,
520 lk_print_usage,
521 lk_print_debug_usage);
njn51d827b2005-05-09 01:02:08 +0000522}
523
sewardj45f4e7c2005-09-27 19:20:21 +0000524VG_DETERMINE_INTERFACE_VERSION(lk_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +0000525
njn25e49d8e72002-09-23 09:36:25 +0000526/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000527/*--- end lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +0000528/*--------------------------------------------------------------------*/