blob: 63ee533859cb9cc9a996ababd3fa29beb0b6b5f7 [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//
njn9dd72772006-03-11 06:48:20 +000041// [Actually, the traces aren't quite right because instructions that modify
42// a memory location are treated like a load followed by a store.]
43//
njnfd73ebb2005-12-30 22:39:58 +000044// If you want to modify how the memory traces are printed/gathered, look at
45// the code that is controlled by the variable 'lk_clo_trace_mem' and the
46// functions 'trace_load()' and 'trace_mem'.. With a bit of effort you
47// should be able to see which other bits of code can be removed, if that's
48// what you want. If you want to do more complex modifications, please read
49// VEX/pub/libvex_ir.h to understand the intermediate representation.
50//
51// For further inspiration, you should look at cachegrind/cg_main.c which
52// handles memory accesses in a more sophisticated way -- it groups them
53// together for processing into twos and threes so that fewer C calls are
54// made and things run faster.
55
njnc7561b92005-06-19 01:24:32 +000056#include "pub_tool_basics.h"
njn43b9a8a2005-05-10 04:37:01 +000057#include "pub_tool_tooliface.h"
njnf39e9a32005-06-12 02:43:17 +000058#include "pub_tool_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000059#include "pub_tool_libcprint.h"
sewardj7a26f022005-11-01 17:52:34 +000060#include "pub_tool_debuginfo.h"
61#include "pub_tool_libcbase.h"
62#include "pub_tool_options.h"
sewardj5fed8c02005-12-23 12:56:11 +000063#include "pub_tool_machine.h" // VG_(fnptr_to_fnentry)
sewardj7a26f022005-11-01 17:52:34 +000064
65/* The name of the function of which the number of calls is to be
66 * counted, with default. Override with command line option
67 * --fnname. */
68static Char* lk_clo_fnname = "_dl_runtime_resolve";
69
70/* If true, show statistics about loads, stores and alu ops. Set
71 * with command line option --detailed-counts. */
72static Bool lk_clo_detailed_counts = False;
73
njnfd73ebb2005-12-30 22:39:58 +000074/* If true, print the trace of loads and stores. Set with --trace-mem. */
75static Bool lk_clo_trace_mem = False;
76
sewardj7a26f022005-11-01 17:52:34 +000077/***********************************************************************
78 * Implement the needs_command_line_options for Valgrind.
79 **********************************************************************/
80
81static Bool lk_process_cmd_line_option(Char* arg)
82{
83 VG_STR_CLO(arg, "--fnname", lk_clo_fnname)
84 else VG_BOOL_CLO(arg, "--detailed-counts", lk_clo_detailed_counts)
njnfd73ebb2005-12-30 22:39:58 +000085 else VG_BOOL_CLO(arg, "--trace-mem", lk_clo_trace_mem)
sewardj7a26f022005-11-01 17:52:34 +000086 else
87 return False;
88
89 tl_assert(lk_clo_fnname);
90 tl_assert(lk_clo_fnname[0]);
91 return True;
92}
93
94static void lk_print_usage(void)
95{
96 VG_(printf)(
97" --fnname=<name> count calls to <name> [_dl_runtime_resolve]\n"
98" --detailed-counts=no|yes count loads, stores and alu ops [no]\n"
99 );
100}
101
102static void lk_print_debug_usage(void)
103{
104}
105
106/***********************************************************************
107 * Data and helpers related to the default operation of Lackey.
108 **********************************************************************/
njn25e49d8e72002-09-23 09:36:25 +0000109
njn25e49d8e72002-09-23 09:36:25 +0000110/* Nb: use ULongs because the numbers can get very big */
sewardj7a26f022005-11-01 17:52:34 +0000111static ULong n_func_calls = 0;
112static ULong n_BBs_entered = 0;
113static ULong n_BBs_completed = 0;
114static ULong n_IRStmts = 0;
115static ULong n_guest_instrs = 0;
116static ULong n_Jccs = 0;
117static ULong n_Jccs_untaken = 0;
njn25e49d8e72002-09-23 09:36:25 +0000118
sewardj7a26f022005-11-01 17:52:34 +0000119static void add_one_func_call(void)
njn25e49d8e72002-09-23 09:36:25 +0000120{
sewardj7a26f022005-11-01 17:52:34 +0000121 n_func_calls++;
njn25e49d8e72002-09-23 09:36:25 +0000122}
123
sewardj7a26f022005-11-01 17:52:34 +0000124static void add_one_BB_entered(void)
njn25e49d8e72002-09-23 09:36:25 +0000125{
sewardj7a26f022005-11-01 17:52:34 +0000126 n_BBs_entered++;
127}
128
129static void add_one_BB_completed(void)
130{
131 n_BBs_completed++;
njn25e49d8e72002-09-23 09:36:25 +0000132}
133
sewardj7a26f022005-11-01 17:52:34 +0000134static void add_one_IRStmt(void)
njn25e49d8e72002-09-23 09:36:25 +0000135{
sewardj7a26f022005-11-01 17:52:34 +0000136 n_IRStmts++;
njn25e49d8e72002-09-23 09:36:25 +0000137}
138
sewardj9f649aa2004-11-22 20:38:40 +0000139static void add_one_guest_instr(void)
njn25e49d8e72002-09-23 09:36:25 +0000140{
sewardj9f649aa2004-11-22 20:38:40 +0000141 n_guest_instrs++;
njn25e49d8e72002-09-23 09:36:25 +0000142}
143
144static void add_one_Jcc(void)
145{
146 n_Jccs++;
147}
148
149static void add_one_Jcc_untaken(void)
150{
151 n_Jccs_untaken++;
152}
153
sewardj7a26f022005-11-01 17:52:34 +0000154/***********************************************************************
155 * Data and helpers related to --detailed-counts.
156 **********************************************************************/
157
158/* --- Operations --- */
159
160typedef enum { OpLoad=0, OpStore=1, OpAlu=2 } Op;
161
162#define N_OPS 3
163
164
165/* --- Types --- */
166
167#define N_TYPES 9
168
169static Int type2index ( IRType ty )
njn25e49d8e72002-09-23 09:36:25 +0000170{
sewardj7a26f022005-11-01 17:52:34 +0000171 switch (ty) {
172 case Ity_I1: return 0;
173 case Ity_I8: return 1;
174 case Ity_I16: return 2;
175 case Ity_I32: return 3;
176 case Ity_I64: return 4;
177 case Ity_I128: return 5;
178 case Ity_F32: return 6;
179 case Ity_F64: return 7;
180 case Ity_V128: return 8;
181 default: tl_assert(0); break;
182 }
njn25e49d8e72002-09-23 09:36:25 +0000183}
184
sewardj7a26f022005-11-01 17:52:34 +0000185static HChar* nameOfTypeIndex ( IRType ty )
186{
187 switch (ty) {
188 case 0: return "I1"; break;
189 case 1: return "I8"; break;
190 case 2: return "I16"; break;
191 case 3: return "I32"; break;
192 case 4: return "I64"; break;
193 case 5: return "I128"; break;
194 case 6: return "F32"; break;
195 case 7: return "F64"; break;
196 case 8: return "V128"; break;
197 default: tl_assert(0); break;
198 }
199}
njn25e49d8e72002-09-23 09:36:25 +0000200
njn25e49d8e72002-09-23 09:36:25 +0000201
sewardj7a26f022005-11-01 17:52:34 +0000202/* --- Counts --- */
njn25e49d8e72002-09-23 09:36:25 +0000203
sewardj7a26f022005-11-01 17:52:34 +0000204static ULong detailCounts[N_OPS][N_TYPES];
njn25e49d8e72002-09-23 09:36:25 +0000205
sewardj7a26f022005-11-01 17:52:34 +0000206/* The helper that is called from the instrumented code. */
207static VG_REGPARM(1)
208void increment_detail(ULong* detail)
209{
210 (*detail)++;
211}
njn25e49d8e72002-09-23 09:36:25 +0000212
sewardj7a26f022005-11-01 17:52:34 +0000213/* A helper that adds the instrumentation for a detail. */
214static void instrument_detail(IRBB* bb, Op op, IRType type)
215{
216 IRDirty* di;
217 IRExpr** argv;
218 const UInt typeIx = type2index(type);
njn25e49d8e72002-09-23 09:36:25 +0000219
sewardj7a26f022005-11-01 17:52:34 +0000220 tl_assert(op < N_OPS);
221 tl_assert(typeIx < N_TYPES);
njn25e49d8e72002-09-23 09:36:25 +0000222
sewardj7a26f022005-11-01 17:52:34 +0000223 argv = mkIRExprVec_1( mkIRExpr_HWord( (HWord)&detailCounts[op][typeIx] ) );
sewardj5fed8c02005-12-23 12:56:11 +0000224 di = unsafeIRDirty_0_N( 1, "increment_detail",
225 VG_(fnptr_to_fnentry)( &increment_detail ),
226 argv);
sewardj7a26f022005-11-01 17:52:34 +0000227 addStmtToIRBB( bb, IRStmt_Dirty(di) );
228}
njn25e49d8e72002-09-23 09:36:25 +0000229
sewardj7a26f022005-11-01 17:52:34 +0000230/* Summarize and print the details. */
njn25e49d8e72002-09-23 09:36:25 +0000231
sewardj7a26f022005-11-01 17:52:34 +0000232static void print_details ( void )
233{
234 Int typeIx;
235 VG_(message)(Vg_UserMsg,
236 " Type Loads Stores AluOps");
237 VG_(message)(Vg_UserMsg,
238 " -------------------------------------------");
239 for (typeIx = 0; typeIx < N_TYPES; typeIx++) {
240 VG_(message)(Vg_UserMsg,
241 " %4s %,12llu %,12llu %,12llu",
242 nameOfTypeIndex( typeIx ),
243 detailCounts[OpLoad ][typeIx],
244 detailCounts[OpStore][typeIx],
245 detailCounts[OpAlu ][typeIx]
246 );
247 }
248}
njn25e49d8e72002-09-23 09:36:25 +0000249
sewardj7a26f022005-11-01 17:52:34 +0000250
251/***********************************************************************
njnfd73ebb2005-12-30 22:39:58 +0000252 * Data and helpers related to --trace-mem.
253 **********************************************************************/
254
255static VG_REGPARM(2) void trace_load(Addr addr, SizeT size)
256{
257 VG_(printf)("load : %p, %d\n", addr, size);
258}
259
260static VG_REGPARM(2) void trace_store(Addr addr, SizeT size)
261{
262 VG_(printf)("store: %p, %d\n", addr, size);
263}
264
265/***********************************************************************
sewardj7a26f022005-11-01 17:52:34 +0000266 * Implement the basic_tool_funcs for Valgrind.
267 **********************************************************************/
268
269static void lk_post_clo_init(void)
270{
271 Int op, tyIx;
272
273 for (op = 0; op < N_OPS; op++)
274 for (tyIx = 0; tyIx < N_TYPES; tyIx++)
275 detailCounts[op][tyIx] = 0;
276}
277
sewardj4ba057c2005-10-18 12:04:18 +0000278static
sewardj461df9c2006-01-17 02:06:39 +0000279IRBB* lk_instrument ( VgCallbackClosure* closure,
280 IRBB* bb_in,
281 VexGuestLayout* layout,
282 VexGuestExtents* vge,
283 IRType gWordTy, IRType hWordTy )
njn25e49d8e72002-09-23 09:36:25 +0000284{
sewardj9f649aa2004-11-22 20:38:40 +0000285 IRDirty* di;
286 Int i;
sewardjd54babf2005-03-21 00:55:49 +0000287 IRBB* bb;
sewardj7a26f022005-11-01 17:52:34 +0000288 Char fnname[100];
289 IRType type;
njnfd73ebb2005-12-30 22:39:58 +0000290 IRExpr** argv;
291 IRExpr* addr_expr;
292 IRExpr* size_expr;
sewardjd54babf2005-03-21 00:55:49 +0000293
294 if (gWordTy != hWordTy) {
295 /* We don't currently support this case. */
296 VG_(tool_panic)("host/guest word size mismatch");
297 }
sewardj9f649aa2004-11-22 20:38:40 +0000298
299 /* Set up BB */
sewardjd54babf2005-03-21 00:55:49 +0000300 bb = emptyIRBB();
sewardj9f649aa2004-11-22 20:38:40 +0000301 bb->tyenv = dopyIRTypeEnv(bb_in->tyenv);
302 bb->next = dopyIRExpr(bb_in->next);
303 bb->jumpkind = bb_in->jumpkind;
304
sewardj7a26f022005-11-01 17:52:34 +0000305 // Copy verbatim any IR preamble preceding the first IMark
306 i = 0;
307 while (i < bb_in->stmts_used && bb_in->stmts[i]->tag != Ist_IMark) {
308 addStmtToIRBB( bb, bb_in->stmts[i] );
309 i++;
sewardj9f649aa2004-11-22 20:38:40 +0000310 }
sewardj9f649aa2004-11-22 20:38:40 +0000311
sewardj7a26f022005-11-01 17:52:34 +0000312 /* Count this basic block. */
sewardj5fed8c02005-12-23 12:56:11 +0000313 di = unsafeIRDirty_0_N( 0, "add_one_BB_entered",
314 VG_(fnptr_to_fnentry)( &add_one_BB_entered ),
sewardj7a26f022005-11-01 17:52:34 +0000315 mkIRExprVec_0() );
sewardj9f649aa2004-11-22 20:38:40 +0000316 addStmtToIRBB( bb, IRStmt_Dirty(di) );
317
sewardj7a26f022005-11-01 17:52:34 +0000318 for (/*use current i*/; i < bb_in->stmts_used; i++) {
sewardj9f649aa2004-11-22 20:38:40 +0000319 IRStmt* st = bb_in->stmts[i];
sewardj7a26f022005-11-01 17:52:34 +0000320 if (!st || st->tag == Ist_NoOp) continue;
sewardj9f649aa2004-11-22 20:38:40 +0000321
sewardj7a26f022005-11-01 17:52:34 +0000322 /* Count one VEX statement. */
sewardj5fed8c02005-12-23 12:56:11 +0000323 di = unsafeIRDirty_0_N( 0, "add_one_IRStmt",
324 VG_(fnptr_to_fnentry)( &add_one_IRStmt ),
sewardj7a26f022005-11-01 17:52:34 +0000325 mkIRExprVec_0() );
326 addStmtToIRBB( bb, IRStmt_Dirty(di) );
327
sewardj9f649aa2004-11-22 20:38:40 +0000328 switch (st->tag) {
sewardj7a26f022005-11-01 17:52:34 +0000329 case Ist_IMark:
330 /* Count guest instruction. */
331 di = unsafeIRDirty_0_N( 0, "add_one_guest_instr",
sewardj5fed8c02005-12-23 12:56:11 +0000332 VG_(fnptr_to_fnentry)( &add_one_guest_instr ),
sewardj7a26f022005-11-01 17:52:34 +0000333 mkIRExprVec_0() );
334 addStmtToIRBB( bb, IRStmt_Dirty(di) );
335
336 /* An unconditional branch to a known destination in the
337 * guest's instructions can be represented, in the IRBB to
338 * instrument, by the VEX statements that are the
339 * translation of that known destination. This feature is
340 * called 'BB chasing' and can be influenced by command
341 * line option --vex-guest-chase-thresh.
342 *
343 * To get an accurate count of the calls to a specific
344 * function, taking BB chasing into account, we need to
345 * check for each guest instruction (Ist_IMark) if it is
346 * the entry point of a function.
347 */
348 tl_assert(lk_clo_fnname);
349 tl_assert(lk_clo_fnname[0]);
350 if (VG_(get_fnname_if_entry)(st->Ist.IMark.addr,
351 fnname, sizeof(fnname))
352 && 0 == VG_(strcmp)(fnname, lk_clo_fnname)) {
sewardj5fed8c02005-12-23 12:56:11 +0000353 di = unsafeIRDirty_0_N(
354 0, "add_one_func_call",
355 VG_(fnptr_to_fnentry)( &add_one_func_call ),
356 mkIRExprVec_0() );
sewardj7a26f022005-11-01 17:52:34 +0000357 addStmtToIRBB( bb, IRStmt_Dirty(di) );
358 }
359 addStmtToIRBB( bb, st );
360 break;
361
sewardj9f649aa2004-11-22 20:38:40 +0000362 case Ist_Exit:
363 /* Count Jcc */
sewardj5fed8c02005-12-23 12:56:11 +0000364 di = unsafeIRDirty_0_N( 0, "add_one_Jcc",
365 VG_(fnptr_to_fnentry)( &add_one_Jcc ),
sewardj7a26f022005-11-01 17:52:34 +0000366 mkIRExprVec_0() );
367 addStmtToIRBB( bb, IRStmt_Dirty(di) );
368
369 addStmtToIRBB( bb, st );
370
sewardj9f649aa2004-11-22 20:38:40 +0000371 /* Count non-taken Jcc */
sewardj7a26f022005-11-01 17:52:34 +0000372 di = unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken",
sewardj5fed8c02005-12-23 12:56:11 +0000373 VG_(fnptr_to_fnentry)( &add_one_Jcc_untaken ),
374 mkIRExprVec_0() );
sewardj7a26f022005-11-01 17:52:34 +0000375 addStmtToIRBB( bb, IRStmt_Dirty(di) );
376 break;
377
378 /* Someone on the users list asked for something like this
379 * just the other day (Christian Stimming, "Fast profiling in
380 * valgrind?", 25 Oct). Personally I think it'd be a
381 * valuable addition.
382 *
383 * Not hard to do either: for stores, examine Ist_Store, and
384 * use typeOfIRExpr(bb->tyenv, st->Ist.Store.data) to get the
385 * store type. For loads and ALU ops, you only need to look
386 * at Ist_Tmp cases where the Ist.Tmp.data is either Iex_Load
387 * or Iex_{Unop,Binop}. All statements you will ever
388 * encounter will satisfy isFlatIRStmt which essentially
389 * constrains them to being flat SSA-style.
390 */
391 case Ist_Store:
njnfd73ebb2005-12-30 22:39:58 +0000392 // Add a call to trace_store() if --trace-mem=yes.
393 if (lk_clo_trace_mem) {
394 addr_expr = st->Ist.Store.addr;
395 size_expr = mkIRExpr_HWord(
396 sizeofIRType(
397 typeOfIRExpr(bb->tyenv, st->Ist.Store.data)));
398 argv = mkIRExprVec_2( addr_expr, size_expr );
399 di = unsafeIRDirty_0_N( /*regparms*/2,
400 "trace_store",
401 VG_(fnptr_to_fnentry)( trace_store ),
402 argv );
403 addStmtToIRBB( bb, IRStmt_Dirty(di) );
404 }
sewardj7a26f022005-11-01 17:52:34 +0000405 if (lk_clo_detailed_counts) {
406 type = typeOfIRExpr(bb->tyenv, st->Ist.Store.data);
407 tl_assert(type != Ity_INVALID);
408 instrument_detail( bb, OpStore, type );
409 }
410 addStmtToIRBB( bb, st );
411 break;
412
413 case Ist_Tmp:
njnfd73ebb2005-12-30 22:39:58 +0000414 // Add a call to trace_load() if --trace-mem=yes.
415 if (lk_clo_trace_mem) {
416 IRExpr* data = st->Ist.Tmp.data;
417 if (data->tag == Iex_Load) {
418 addr_expr = data->Iex.Load.addr;
419 size_expr = mkIRExpr_HWord( sizeofIRType(data->Iex.Load.ty) );
420 argv = mkIRExprVec_2( addr_expr, size_expr );
421 di = unsafeIRDirty_0_N( /*regparms*/2,
422 "trace_load",
423 VG_(fnptr_to_fnentry)( trace_load ),
424 argv );
425 addStmtToIRBB( bb, IRStmt_Dirty(di) );
426 }
427 }
sewardj7a26f022005-11-01 17:52:34 +0000428 if (lk_clo_detailed_counts) {
429 IRExpr* expr = st->Ist.Tmp.data;
430 type = typeOfIRExpr(bb->tyenv, expr);
431 tl_assert(type != Ity_INVALID);
432 switch (expr->tag) {
433 case Iex_Load:
434 instrument_detail( bb, OpLoad, type );
435 break;
436 case Iex_Unop:
437 case Iex_Binop:
sewardje91cea72006-02-08 19:32:02 +0000438 case Iex_Triop:
439 case Iex_Qop:
sewardj7a26f022005-11-01 17:52:34 +0000440 case Iex_Mux0X:
441 instrument_detail( bb, OpAlu, type );
442 break;
443 default:
444 break;
445 }
446 }
447 addStmtToIRBB( bb, st );
sewardj9f649aa2004-11-22 20:38:40 +0000448 break;
449
450 default:
sewardjbd598e12005-01-07 12:10:21 +0000451 addStmtToIRBB( bb, st );
sewardj9f649aa2004-11-22 20:38:40 +0000452 }
453 }
454
sewardj7a26f022005-11-01 17:52:34 +0000455 /* Count this basic block. */
456 di = unsafeIRDirty_0_N( 0, "add_one_BB_completed",
sewardj5fed8c02005-12-23 12:56:11 +0000457 VG_(fnptr_to_fnentry)( &add_one_BB_completed ),
458 mkIRExprVec_0() );
sewardj7a26f022005-11-01 17:52:34 +0000459 addStmtToIRBB( bb, IRStmt_Dirty(di) );
460
sewardj9f649aa2004-11-22 20:38:40 +0000461 return bb;
njn25e49d8e72002-09-23 09:36:25 +0000462}
463
njn51d827b2005-05-09 01:02:08 +0000464static void lk_fini(Int exitcode)
njn25e49d8e72002-09-23 09:36:25 +0000465{
sewardj7a26f022005-11-01 17:52:34 +0000466 char percentify_buf[4]; /* Two digits, '%' and 0. */
467 const int percentify_size = sizeof(percentify_buf);
468 const int percentify_decs = 0;
469
470 tl_assert(lk_clo_fnname);
471 tl_assert(lk_clo_fnname[0]);
472 VG_(message)(Vg_UserMsg,
473 "Counted %,llu calls to %s()", n_func_calls, lk_clo_fnname);
njn25e49d8e72002-09-23 09:36:25 +0000474
sewardj7a26f022005-11-01 17:52:34 +0000475 VG_(message)(Vg_UserMsg, "");
476 VG_(message)(Vg_UserMsg, "Jccs:");
477 VG_(message)(Vg_UserMsg, " total: %,llu", n_Jccs);
478 VG_(percentify)((n_Jccs - n_Jccs_untaken), (n_Jccs ? n_Jccs : 1),
479 percentify_decs, percentify_size, percentify_buf);
480 VG_(message)(Vg_UserMsg, " taken: %,llu (%s)",
481 (n_Jccs - n_Jccs_untaken), percentify_buf);
482
483 VG_(message)(Vg_UserMsg, "");
484 VG_(message)(Vg_UserMsg, "Executed:");
485 VG_(message)(Vg_UserMsg, " BBs entered: %,llu", n_BBs_entered);
486 VG_(message)(Vg_UserMsg, " BBs completed: %,llu", n_BBs_completed);
487 VG_(message)(Vg_UserMsg, " guest instrs: %,llu", n_guest_instrs);
488 VG_(message)(Vg_UserMsg, " IRStmts: %,llu", n_IRStmts);
489
490 VG_(message)(Vg_UserMsg, "");
491 VG_(message)(Vg_UserMsg, "Ratios:");
492 tl_assert(n_BBs_entered); // Paranoia time.
493 VG_(message)(Vg_UserMsg, " guest instrs : BB entered = %3u : 10",
494 10 * n_guest_instrs / n_BBs_entered);
495 VG_(message)(Vg_UserMsg, " IRStmts : BB entered = %3u : 10",
496 10 * n_IRStmts / n_BBs_entered);
497 tl_assert(n_guest_instrs); // Paranoia time.
498 VG_(message)(Vg_UserMsg, " IRStmts : guest instr = %3u : 10",
499 10 * n_IRStmts / n_guest_instrs);
njn25e49d8e72002-09-23 09:36:25 +0000500
sewardj7a26f022005-11-01 17:52:34 +0000501 if (lk_clo_detailed_counts) {
502 VG_(message)(Vg_UserMsg, "");
503 VG_(message)(Vg_UserMsg, "IR-level counts by type:");
504 print_details();
505 }
njn25e49d8e72002-09-23 09:36:25 +0000506
sewardj7a26f022005-11-01 17:52:34 +0000507 VG_(message)(Vg_UserMsg, "");
508 VG_(message)(Vg_UserMsg, "Exit code: %d", exitcode);
njn25e49d8e72002-09-23 09:36:25 +0000509}
510
njn51d827b2005-05-09 01:02:08 +0000511static void lk_pre_clo_init(void)
512{
513 VG_(details_name) ("Lackey");
514 VG_(details_version) (NULL);
515 VG_(details_description) ("an example Valgrind tool");
516 VG_(details_copyright_author)(
517 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote.");
518 VG_(details_bug_reports_to) (VG_BUGS_TO);
519 VG_(details_avg_translation_sizeB) ( 175 );
520
521 VG_(basic_tool_funcs) (lk_post_clo_init,
522 lk_instrument,
523 lk_fini);
sewardj7a26f022005-11-01 17:52:34 +0000524 VG_(needs_command_line_options)(lk_process_cmd_line_option,
525 lk_print_usage,
526 lk_print_debug_usage);
njn51d827b2005-05-09 01:02:08 +0000527}
528
sewardj45f4e7c2005-09-27 19:20:21 +0000529VG_DETERMINE_INTERFACE_VERSION(lk_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +0000530
njn25e49d8e72002-09-23 09:36:25 +0000531/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000532/*--- end lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +0000533/*--------------------------------------------------------------------*/