lk_main.c revision 51d827bcd88ce045a383ea1ca81768757df2d1fa
1 2/*--------------------------------------------------------------------*/ 3/*--- Simple tool for counting UInstrs, using a C helper. ---*/ 4/*--- lk_main.c ---*/ 5/*--------------------------------------------------------------------*/ 6 7/* 8 This file is part of Lackey, an example Valgrind tool that does 9 some simple program measurement. 10 11 Copyright (C) 2002-2005 Nicholas Nethercote 12 njn@valgrind.org 13 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 32#include "tool.h" 33 34/* Nb: use ULongs because the numbers can get very big */ 35static ULong n_dlrr_calls = 0; 36static ULong n_BBs = 0; 37static ULong n_UInstrs = 0; 38static ULong n_guest_instrs = 0; 39static ULong n_Jccs = 0; 40static ULong n_Jccs_untaken = 0; 41 42static void add_one_dlrr_call(void) 43{ 44 n_dlrr_calls++; 45} 46 47/* See comment above lk_instrument for reason why n_machine_instrs is 48 incremented here. */ 49static void add_one_BB(void) 50{ 51 n_BBs++; 52 n_guest_instrs++; 53} 54 55static void add_one_UInstr(void) 56{ 57 n_UInstrs++; 58} 59 60static void add_one_guest_instr(void) 61{ 62 n_guest_instrs++; 63} 64 65static void add_one_Jcc(void) 66{ 67 n_Jccs++; 68} 69 70static void add_one_Jcc_untaken(void) 71{ 72 n_Jccs_untaken++; 73} 74 75static void lk_post_clo_init(void) 76{ 77} 78 79/* Note: machine instructions are marked by an INCEIP at the end of each one, 80 except for the final one in the basic block which ends in an 81 unconditional JMP. Sometimes the final unconditional JMP is preceded by 82 a conditional JMP (Jcc), and thus it isn't reached. Eg: 83 84 <code a> 85 INCEIP ... 86 87 <code b> 88 Jcc ... 89 JMP ... (will not be reached if Jcc succeeds) 90 91 If we simplemindedly added calls to add_one_guest_instr() before INCEIPs 92 and unconditional JMPs, we'd sometimes miss the final call (when a 93 preceding conditional JMP succeeds), underestimating the machine instruction 94 count. 95 96 <code a> 97 call add_one_guest_instr() 98 INCEIP ... 99 100 <code b> 101 Jcc ... 102 call add_one_guest_instr() 103 JMP ... 104 105 Instead we add a call before each INCEIP, and also one at the start of the 106 block, but not one at the end, viz: 107 108 call add_one_guest_instr() 109 110 <code a> 111 call add_one_guest_instr() 112 INCEIP ... 113 114 <code b> 115 Jcc ... 116 JMP ... 117 118 Which gives us the right answer. And just to avoid two C calls, we fold 119 the basic-block-beginning call in with add_one_BB(). Phew. 120*/ 121static IRBB* lk_instrument(IRBB* bb_in, VexGuestLayout* layout, 122 IRType gWordTy, IRType hWordTy ) 123{ 124 IRDirty* di; 125 Int i; 126 IRBB* bb; 127 128 if (gWordTy != hWordTy) { 129 /* We don't currently support this case. */ 130 VG_(tool_panic)("host/guest word size mismatch"); 131 } 132 133 /* Set up BB */ 134 bb = emptyIRBB(); 135 bb->tyenv = dopyIRTypeEnv(bb_in->tyenv); 136 bb->next = dopyIRExpr(bb_in->next); 137 bb->jumpkind = bb_in->jumpkind; 138 139#if 0 140 /* We need to know the entry point for this bb to do this. In any 141 case it's pretty meaningless in the presence of bb chasing since 142 we may enter this function part way through an IRBB. */ 143 /* Count call to dlrr(), if this BB is dlrr()'s entry point */ 144 if (VG_(get_fnname_if_entry)(orig_addr, fnname, 100) && 145 0 == VG_(strcmp)(fnname, "_dl_runtime_resolve")) 146 { 147 addStmtToIRBB( 148 bb, 149 IRStmt_Dirty( 150 unsafeIRDirty_0_N( "add_one_dlrr_call", mkIRExprVec_0() ) 151 )); 152 } 153#endif 154 155 /* Count this basic block */ 156 di = unsafeIRDirty_0_N( 0, "add_one_BB", &add_one_BB, mkIRExprVec_0() ); 157 addStmtToIRBB( bb, IRStmt_Dirty(di) ); 158 159 for (i = 0; i < bb_in->stmts_used; i++) { 160 IRStmt* st = bb_in->stmts[i]; 161 if (!st) continue; 162 163 switch (st->tag) { 164 case Ist_Exit: 165 /* Count Jcc */ 166 addStmtToIRBB( 167 bb, 168 IRStmt_Dirty( 169 unsafeIRDirty_0_N( 0, "add_one_Jcc", &add_one_Jcc, 170 mkIRExprVec_0() ) 171 )); 172 addStmtToIRBB( bb, dopyIRStmt(st) ); 173 /* Count non-taken Jcc */ 174 addStmtToIRBB( 175 bb, 176 IRStmt_Dirty( 177 unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken", &add_one_Jcc_untaken, 178 mkIRExprVec_0() ) 179 )); 180 break; 181 182 default: 183 addStmtToIRBB( bb, st ); 184 } 185 } 186 187 return bb; 188 189 190#if 0 191 UCodeBlock* cb; 192 Int i; 193 UInstr* u; 194 Char fnname[100]; 195 196 cb = VG_(setup_UCodeBlock)(cb_in); 197 198 /* Count basic block */ 199 VG_(call_helper_0_0)(cb, (Addr) & add_one_BB); 200 201 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) { 202 u = VG_(get_instr)(cb_in, i); 203 204 switch (u->opcode) { 205 case NOP: case LOCK: case CALLM_S: case CALLM_E: 206 break; 207 208 case INCEIP: 209 /* Count x86 instr */ 210 VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr); 211 VG_(copy_UInstr)(cb, u); 212 break; 213 214 case JMP: 215 if (u->cond != CondAlways) { 216 /* Count Jcc */ 217 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc); 218 VG_(copy_UInstr)(cb, u); 219 /* Count non-taken Jcc */ 220 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken); 221 } else { 222 VG_(copy_UInstr)(cb, u); 223 } 224 break; 225 226 default: 227 /* Count UInstr */ 228 VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr); 229 VG_(copy_UInstr)(cb, u); 230 break; 231 } 232 } 233 234 VG_(free_UCodeBlock)(cb_in); 235 return cb; 236#endif 237} 238 239static void lk_fini(Int exitcode) 240{ 241 VG_(message)(Vg_UserMsg, 242 "Counted %d calls to _dl_runtime_resolve()", n_dlrr_calls); 243 244 VG_(message)(Vg_UserMsg, ""); 245 VG_(message)(Vg_UserMsg, "Executed:"); 246 VG_(message)(Vg_UserMsg, " BBs: %u", n_BBs); 247 VG_(message)(Vg_UserMsg, " guest instrs: %u", n_guest_instrs); 248 VG_(message)(Vg_UserMsg, " UInstrs: %u", n_UInstrs); 249 250 VG_(message)(Vg_UserMsg, ""); 251 VG_(message)(Vg_UserMsg, "Jccs:"); 252 VG_(message)(Vg_UserMsg, " total: %u", n_Jccs); 253 VG_(message)(Vg_UserMsg, " %% taken: %u%%", 254 (n_Jccs - n_Jccs_untaken)*100 / 255 (n_Jccs ? n_Jccs : 1)); 256 257 VG_(message)(Vg_UserMsg, ""); 258 VG_(message)(Vg_UserMsg, "Ratios:"); 259 VG_(message)(Vg_UserMsg, " guest instrs : BB = %3u : 10", 260 10 * n_guest_instrs / n_BBs); 261 VG_(message)(Vg_UserMsg, " UInstrs : BB = %3u : 10", 262 10 * n_UInstrs / n_BBs); 263 VG_(message)(Vg_UserMsg, " UInstrs : x86_instr = %3u : 10", 264 10 * n_UInstrs / n_guest_instrs); 265 266 VG_(message)(Vg_UserMsg, ""); 267 VG_(message)(Vg_UserMsg, "Exit code: %d", exitcode); 268} 269 270static void lk_pre_clo_init(void) 271{ 272 VG_(details_name) ("Lackey"); 273 VG_(details_version) (NULL); 274 VG_(details_description) ("an example Valgrind tool"); 275 VG_(details_copyright_author)( 276 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote."); 277 VG_(details_bug_reports_to) (VG_BUGS_TO); 278 VG_(details_avg_translation_sizeB) ( 175 ); 279 280 VG_(basic_tool_funcs) (lk_post_clo_init, 281 lk_instrument, 282 lk_fini); 283} 284 285VG_DETERMINE_INTERFACE_VERSION(lk_pre_clo_init, 0) 286 287/*--------------------------------------------------------------------*/ 288/*--- end lk_main.c ---*/ 289/*--------------------------------------------------------------------*/ 290 291