diff options
author | njn <njn@a5019735-40e9-0310-863c-91ae7b9d1cf9> | 2006-04-07 11:52:55 +0000 |
---|---|---|
committer | njn <njn@a5019735-40e9-0310-863c-91ae7b9d1cf9> | 2006-04-07 11:52:55 +0000 |
commit | d99644db668b2177b2e546a831b8223648936445 (patch) | |
tree | dbc67ea00ff744bc6e9c318b8e00d0d3c26283f9 /lackey | |
parent | 8c20d87e73ec282b3805d725b78dedf9898ce769 (diff) |
Tweaked Lackey. Main change is that the default instrumentation is now only
added if you specify --basic-counts=yes (which is the default). So
all of the instrumentation is now controlled by a command-line option (one
of --basic-counts, --detailed-counts or --trace-mem) and so if you turn them
all off it behaves like Nulgrind. This makes it clearer what's going on and
easier for newbies to modify.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@5834 a5019735-40e9-0310-863c-91ae7b9d1cf9
Diffstat (limited to 'lackey')
-rw-r--r-- | lackey/lk_main.c | 330 |
1 files changed, 177 insertions, 153 deletions
diff --git a/lackey/lk_main.c b/lackey/lk_main.c index 63ee5338..975fb573 100644 --- a/lackey/lk_main.c +++ b/lackey/lk_main.c @@ -1,12 +1,11 @@ /*--------------------------------------------------------------------*/ -/*--- An example Valgrind tool. ---*/ -/*--- lk_main.c ---*/ +/*--- An example Valgrind tool. lk_main.c ---*/ /*--------------------------------------------------------------------*/ /* This file is part of Lackey, an example Valgrind tool that does - some simple program measurement. + some simple program measurement and tracing. Copyright (C) 2002-2005 Nicholas Nethercote njn@valgrind.org @@ -31,23 +30,36 @@ // This tool shows how to do some basic instrumentation. // -// In particular, if you are interested in tracing every load and store a -// program does, use the --trace-mem=yes option. Please note that the -// address trace is good, but not perfect; see Section 3.3.7 of Nicholas -// Nethercote's PhD dissertation "Dynamic Binary Analysis and -// Instrumentation", 2004, for details about the few loads and stores that -// it misses, and other caveats about the accuracy of the address trace. +// There are three kinds of instrumentation it can do. They can be turned +// on/off independently with command line options: // -// [Actually, the traces aren't quite right because instructions that modify -// a memory location are treated like a load followed by a store.] +// * --basic-counts : do basic counts, eg. number of instructions +// executed, jumps executed, etc. +// * --detailed-counts: do more detailed counts: number of loads, stores +// and ALU operations of different sizes. +// * --trace-mem=yes: trace all (data) memory accesses. +// +// The code for each kind of instrumentation is guarded by a clo_* variable: +// clo_basic_counts, clo_detailed_counts and clo_trace_mem. // -// If you want to modify how the memory traces are printed/gathered, look at -// the code that is controlled by the variable 'lk_clo_trace_mem' and the -// functions 'trace_load()' and 'trace_mem'.. With a bit of effort you -// should be able to see which other bits of code can be removed, if that's -// what you want. If you want to do more complex modifications, please read +// If you want to modify any of the instrumentation code, look for the code +// that is guarded by the relevant clo_* variable (eg. clo_trace_mem) +// If you're not interested in the other kinds of instrumentation you can +// remove them. If you want to do more complex modifications, please read // VEX/pub/libvex_ir.h to understand the intermediate representation. // +// +// Specific Details about --trace-mem=yes +// -------------------------------------- +// The address trace produced by --trace-mem=yes is good, but not perfect; +// see Section 3.3.7 of Nicholas Nethercote's PhD dissertation "Dynamic +// Binary Analysis and Instrumentation", 2004, for details about the few +// loads and stores that it misses, and other caveats about the accuracy of +// the address trace. +// +// [Actually, the traces aren't quite right because instructions that modify +// a memory location are treated like a load followed by a store.] +// // For further inspiration, you should look at cachegrind/cg_main.c which // handles memory accesses in a more sophisticated way -- it groups them // together for processing into twos and threes so that fewer C calls are @@ -62,40 +74,44 @@ #include "pub_tool_options.h" #include "pub_tool_machine.h" // VG_(fnptr_to_fnentry) -/* The name of the function of which the number of calls is to be - * counted, with default. Override with command line option - * --fnname. */ -static Char* lk_clo_fnname = "_dl_runtime_resolve"; - -/* If true, show statistics about loads, stores and alu ops. Set - * with command line option --detailed-counts. */ -static Bool lk_clo_detailed_counts = False; +/*------------------------------------------------------------*/ +/*--- Command line options ---*/ +/*------------------------------------------------------------*/ -/* If true, print the trace of loads and stores. Set with --trace-mem. */ -static Bool lk_clo_trace_mem = False; +/* Command line options controlling instrumentation kinds, as described at + * the top of this file. */ +static Bool clo_basic_counts = True; +static Bool clo_detailed_counts = False; +static Bool clo_trace_mem = False; -/*********************************************************************** - * Implement the needs_command_line_options for Valgrind. - **********************************************************************/ +/* The name of the function of which the number of calls (under + * --basic-counts=yes) is to be counted, with default. Override with command + * line option --fnname. */ +static Char* clo_fnname = "_dl_runtime_resolve"; static Bool lk_process_cmd_line_option(Char* arg) { - VG_STR_CLO(arg, "--fnname", lk_clo_fnname) - else VG_BOOL_CLO(arg, "--detailed-counts", lk_clo_detailed_counts) - else VG_BOOL_CLO(arg, "--trace-mem", lk_clo_trace_mem) + VG_STR_CLO(arg, "--fnname", clo_fnname) + else VG_BOOL_CLO(arg, "--basic-counts", clo_basic_counts) + else VG_BOOL_CLO(arg, "--detailed-counts", clo_detailed_counts) + else VG_BOOL_CLO(arg, "--trace-mem", clo_trace_mem) else return False; - tl_assert(lk_clo_fnname); - tl_assert(lk_clo_fnname[0]); + tl_assert(clo_fnname); + tl_assert(clo_fnname[0]); return True; } static void lk_print_usage(void) { VG_(printf)( -" --fnname=<name> count calls to <name> [_dl_runtime_resolve]\n" +" --basic-counts=no|yes count instructions, jumps, etc. [no]\n" " --detailed-counts=no|yes count loads, stores and alu ops [no]\n" +" --trace-mem=no|yes trace all loads and stores [no]\n" +" --fnname=<name> count calls to <name> (only used if\n" +" --basic-count=yes) [_dl_runtime_resolve]\n" + ); } @@ -103,9 +119,9 @@ static void lk_print_debug_usage(void) { } -/*********************************************************************** - * Data and helpers related to the default operation of Lackey. - **********************************************************************/ +/*------------------------------------------------------------*/ +/*--- Data and helpers for --basic-counts ---*/ +/*------------------------------------------------------------*/ /* Nb: use ULongs because the numbers can get very big */ static ULong n_func_calls = 0; @@ -151,9 +167,9 @@ static void add_one_Jcc_untaken(void) n_Jccs_untaken++; } -/*********************************************************************** - * Data and helpers related to --detailed-counts. - **********************************************************************/ +/*------------------------------------------------------------*/ +/*--- Data and helpers for --detailed-counts ---*/ +/*------------------------------------------------------------*/ /* --- Operations --- */ @@ -248,9 +264,9 @@ static void print_details ( void ) } -/*********************************************************************** - * Data and helpers related to --trace-mem. - **********************************************************************/ +/*------------------------------------------------------------*/ +/*--- Data and helpers for --trace-mem ---*/ +/*------------------------------------------------------------*/ static VG_REGPARM(2) void trace_load(Addr addr, SizeT size) { @@ -262,17 +278,20 @@ static VG_REGPARM(2) void trace_store(Addr addr, SizeT size) VG_(printf)("store: %p, %d\n", addr, size); } -/*********************************************************************** - * Implement the basic_tool_funcs for Valgrind. - **********************************************************************/ + +/*------------------------------------------------------------*/ +/*--- Basic tool functions ---*/ +/*------------------------------------------------------------*/ static void lk_post_clo_init(void) { Int op, tyIx; - for (op = 0; op < N_OPS; op++) - for (tyIx = 0; tyIx < N_TYPES; tyIx++) - detailCounts[op][tyIx] = 0; + if (clo_detailed_counts) { + for (op = 0; op < N_OPS; op++) + for (tyIx = 0; tyIx < N_TYPES; tyIx++) + detailCounts[op][tyIx] = 0; + } } static @@ -309,88 +328,86 @@ IRBB* lk_instrument ( VgCallbackClosure* closure, i++; } - /* Count this basic block. */ - di = unsafeIRDirty_0_N( 0, "add_one_BB_entered", - VG_(fnptr_to_fnentry)( &add_one_BB_entered ), - mkIRExprVec_0() ); - addStmtToIRBB( bb, IRStmt_Dirty(di) ); + if (clo_basic_counts) { + /* Count this basic block. */ + di = unsafeIRDirty_0_N( 0, "add_one_BB_entered", + VG_(fnptr_to_fnentry)( &add_one_BB_entered ), + mkIRExprVec_0() ); + addStmtToIRBB( bb, IRStmt_Dirty(di) ); + } for (/*use current i*/; i < bb_in->stmts_used; i++) { IRStmt* st = bb_in->stmts[i]; if (!st || st->tag == Ist_NoOp) continue; - /* Count one VEX statement. */ - di = unsafeIRDirty_0_N( 0, "add_one_IRStmt", - VG_(fnptr_to_fnentry)( &add_one_IRStmt ), - mkIRExprVec_0() ); - addStmtToIRBB( bb, IRStmt_Dirty(di) ); + if (clo_basic_counts) { + /* Count one VEX statement. */ + di = unsafeIRDirty_0_N( 0, "add_one_IRStmt", + VG_(fnptr_to_fnentry)( &add_one_IRStmt ), + mkIRExprVec_0() ); + addStmtToIRBB( bb, IRStmt_Dirty(di) ); + } switch (st->tag) { case Ist_IMark: - /* Count guest instruction. */ - di = unsafeIRDirty_0_N( 0, "add_one_guest_instr", - VG_(fnptr_to_fnentry)( &add_one_guest_instr ), - mkIRExprVec_0() ); - addStmtToIRBB( bb, IRStmt_Dirty(di) ); - - /* An unconditional branch to a known destination in the - * guest's instructions can be represented, in the IRBB to - * instrument, by the VEX statements that are the - * translation of that known destination. This feature is - * called 'BB chasing' and can be influenced by command - * line option --vex-guest-chase-thresh. - * - * To get an accurate count of the calls to a specific - * function, taking BB chasing into account, we need to - * check for each guest instruction (Ist_IMark) if it is - * the entry point of a function. - */ - tl_assert(lk_clo_fnname); - tl_assert(lk_clo_fnname[0]); - if (VG_(get_fnname_if_entry)(st->Ist.IMark.addr, - fnname, sizeof(fnname)) - && 0 == VG_(strcmp)(fnname, lk_clo_fnname)) { - di = unsafeIRDirty_0_N( - 0, "add_one_func_call", - VG_(fnptr_to_fnentry)( &add_one_func_call ), - mkIRExprVec_0() ); + if (clo_basic_counts) { + /* Count guest instruction. */ + di = unsafeIRDirty_0_N( 0, "add_one_guest_instr", + VG_(fnptr_to_fnentry)( &add_one_guest_instr ), + mkIRExprVec_0() ); addStmtToIRBB( bb, IRStmt_Dirty(di) ); + + /* An unconditional branch to a known destination in the + * guest's instructions can be represented, in the IRBB to + * instrument, by the VEX statements that are the + * translation of that known destination. This feature is + * called 'BB chasing' and can be influenced by command + * line option --vex-guest-chase-thresh. + * + * To get an accurate count of the calls to a specific + * function, taking BB chasing into account, we need to + * check for each guest instruction (Ist_IMark) if it is + * the entry point of a function. + */ + tl_assert(clo_fnname); + tl_assert(clo_fnname[0]); + if (VG_(get_fnname_if_entry)(st->Ist.IMark.addr, + fnname, sizeof(fnname)) + && 0 == VG_(strcmp)(fnname, clo_fnname)) { + di = unsafeIRDirty_0_N( + 0, "add_one_func_call", + VG_(fnptr_to_fnentry)( &add_one_func_call ), + mkIRExprVec_0() ); + addStmtToIRBB( bb, IRStmt_Dirty(di) ); + } } addStmtToIRBB( bb, st ); break; case Ist_Exit: - /* Count Jcc */ - di = unsafeIRDirty_0_N( 0, "add_one_Jcc", - VG_(fnptr_to_fnentry)( &add_one_Jcc ), - mkIRExprVec_0() ); - addStmtToIRBB( bb, IRStmt_Dirty(di) ); + if (clo_basic_counts) { + /* Count Jcc */ + di = unsafeIRDirty_0_N( 0, "add_one_Jcc", + VG_(fnptr_to_fnentry)( &add_one_Jcc ), + mkIRExprVec_0() ); + addStmtToIRBB( bb, IRStmt_Dirty(di) ); + } addStmtToIRBB( bb, st ); - /* Count non-taken Jcc */ - di = unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken", - VG_(fnptr_to_fnentry)( &add_one_Jcc_untaken ), - mkIRExprVec_0() ); - addStmtToIRBB( bb, IRStmt_Dirty(di) ); + if (clo_basic_counts) { + /* Count non-taken Jcc */ + di = unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken", + VG_(fnptr_to_fnentry)( + &add_one_Jcc_untaken ), + mkIRExprVec_0() ); + addStmtToIRBB( bb, IRStmt_Dirty(di) ); + } break; - /* Someone on the users list asked for something like this - * just the other day (Christian Stimming, "Fast profiling in - * valgrind?", 25 Oct). Personally I think it'd be a - * valuable addition. - * - * Not hard to do either: for stores, examine Ist_Store, and - * use typeOfIRExpr(bb->tyenv, st->Ist.Store.data) to get the - * store type. For loads and ALU ops, you only need to look - * at Ist_Tmp cases where the Ist.Tmp.data is either Iex_Load - * or Iex_{Unop,Binop}. All statements you will ever - * encounter will satisfy isFlatIRStmt which essentially - * constrains them to being flat SSA-style. - */ case Ist_Store: // Add a call to trace_store() if --trace-mem=yes. - if (lk_clo_trace_mem) { + if (clo_trace_mem) { addr_expr = st->Ist.Store.addr; size_expr = mkIRExpr_HWord( sizeofIRType( @@ -402,7 +419,7 @@ IRBB* lk_instrument ( VgCallbackClosure* closure, argv ); addStmtToIRBB( bb, IRStmt_Dirty(di) ); } - if (lk_clo_detailed_counts) { + if (clo_detailed_counts) { type = typeOfIRExpr(bb->tyenv, st->Ist.Store.data); tl_assert(type != Ity_INVALID); instrument_detail( bb, OpStore, type ); @@ -412,7 +429,7 @@ IRBB* lk_instrument ( VgCallbackClosure* closure, case Ist_Tmp: // Add a call to trace_load() if --trace-mem=yes. - if (lk_clo_trace_mem) { + if (clo_trace_mem) { IRExpr* data = st->Ist.Tmp.data; if (data->tag == Iex_Load) { addr_expr = data->Iex.Load.addr; @@ -425,7 +442,7 @@ IRBB* lk_instrument ( VgCallbackClosure* closure, addStmtToIRBB( bb, IRStmt_Dirty(di) ); } } - if (lk_clo_detailed_counts) { + if (clo_detailed_counts) { IRExpr* expr = st->Ist.Tmp.data; type = typeOfIRExpr(bb->tyenv, expr); tl_assert(type != Ity_INVALID); @@ -452,11 +469,13 @@ IRBB* lk_instrument ( VgCallbackClosure* closure, } } - /* Count this basic block. */ - di = unsafeIRDirty_0_N( 0, "add_one_BB_completed", - VG_(fnptr_to_fnentry)( &add_one_BB_completed ), - mkIRExprVec_0() ); - addStmtToIRBB( bb, IRStmt_Dirty(di) ); + if (clo_basic_counts) { + /* Count this basic block. */ + di = unsafeIRDirty_0_N( 0, "add_one_BB_completed", + VG_(fnptr_to_fnentry)( &add_one_BB_completed ), + mkIRExprVec_0() ); + addStmtToIRBB( bb, IRStmt_Dirty(di) ); + } return bb; } @@ -467,45 +486,50 @@ static void lk_fini(Int exitcode) const int percentify_size = sizeof(percentify_buf); const int percentify_decs = 0; - tl_assert(lk_clo_fnname); - tl_assert(lk_clo_fnname[0]); - VG_(message)(Vg_UserMsg, - "Counted %,llu calls to %s()", n_func_calls, lk_clo_fnname); - - VG_(message)(Vg_UserMsg, ""); - VG_(message)(Vg_UserMsg, "Jccs:"); - VG_(message)(Vg_UserMsg, " total: %,llu", n_Jccs); - VG_(percentify)((n_Jccs - n_Jccs_untaken), (n_Jccs ? n_Jccs : 1), - percentify_decs, percentify_size, percentify_buf); - VG_(message)(Vg_UserMsg, " taken: %,llu (%s)", - (n_Jccs - n_Jccs_untaken), percentify_buf); - - VG_(message)(Vg_UserMsg, ""); - VG_(message)(Vg_UserMsg, "Executed:"); - VG_(message)(Vg_UserMsg, " BBs entered: %,llu", n_BBs_entered); - VG_(message)(Vg_UserMsg, " BBs completed: %,llu", n_BBs_completed); - VG_(message)(Vg_UserMsg, " guest instrs: %,llu", n_guest_instrs); - VG_(message)(Vg_UserMsg, " IRStmts: %,llu", n_IRStmts); - - VG_(message)(Vg_UserMsg, ""); - VG_(message)(Vg_UserMsg, "Ratios:"); - tl_assert(n_BBs_entered); // Paranoia time. - VG_(message)(Vg_UserMsg, " guest instrs : BB entered = %3u : 10", - 10 * n_guest_instrs / n_BBs_entered); - VG_(message)(Vg_UserMsg, " IRStmts : BB entered = %3u : 10", - 10 * n_IRStmts / n_BBs_entered); - tl_assert(n_guest_instrs); // Paranoia time. - VG_(message)(Vg_UserMsg, " IRStmts : guest instr = %3u : 10", - 10 * n_IRStmts / n_guest_instrs); - - if (lk_clo_detailed_counts) { + tl_assert(clo_fnname); + tl_assert(clo_fnname[0]); + + if (clo_basic_counts) { + VG_(message)(Vg_UserMsg, + "Counted %,llu calls to %s()", n_func_calls, clo_fnname); + + VG_(message)(Vg_UserMsg, ""); + VG_(message)(Vg_UserMsg, "Jccs:"); + VG_(message)(Vg_UserMsg, " total: %,llu", n_Jccs); + VG_(percentify)((n_Jccs - n_Jccs_untaken), (n_Jccs ? n_Jccs : 1), + percentify_decs, percentify_size, percentify_buf); + VG_(message)(Vg_UserMsg, " taken: %,llu (%s)", + (n_Jccs - n_Jccs_untaken), percentify_buf); + + VG_(message)(Vg_UserMsg, ""); + VG_(message)(Vg_UserMsg, "Executed:"); + VG_(message)(Vg_UserMsg, " BBs entered: %,llu", n_BBs_entered); + VG_(message)(Vg_UserMsg, " BBs completed: %,llu", n_BBs_completed); + VG_(message)(Vg_UserMsg, " guest instrs: %,llu", n_guest_instrs); + VG_(message)(Vg_UserMsg, " IRStmts: %,llu", n_IRStmts); + + VG_(message)(Vg_UserMsg, ""); + VG_(message)(Vg_UserMsg, "Ratios:"); + tl_assert(n_BBs_entered); // Paranoia time. + VG_(message)(Vg_UserMsg, " guest instrs : BB entered = %3u : 10", + 10 * n_guest_instrs / n_BBs_entered); + VG_(message)(Vg_UserMsg, " IRStmts : BB entered = %3u : 10", + 10 * n_IRStmts / n_BBs_entered); + tl_assert(n_guest_instrs); // Paranoia time. + VG_(message)(Vg_UserMsg, " IRStmts : guest instr = %3u : 10", + 10 * n_IRStmts / n_guest_instrs); + } + + if (clo_detailed_counts) { VG_(message)(Vg_UserMsg, ""); VG_(message)(Vg_UserMsg, "IR-level counts by type:"); print_details(); } - VG_(message)(Vg_UserMsg, ""); - VG_(message)(Vg_UserMsg, "Exit code: %d", exitcode); + if (clo_basic_counts) { + VG_(message)(Vg_UserMsg, ""); + VG_(message)(Vg_UserMsg, "Exit code: %d", exitcode); + } } static void lk_pre_clo_init(void) |