lk_main.c revision 5361242f022b38fadb4cdf02428cea8b8d901a90
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 njn25@cam.ac.uk 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 TL_(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 75void TL_(pre_clo_init)(void) 76{ 77 VG_(details_name) ("Lackey"); 78 VG_(details_version) (NULL); 79 VG_(details_description) ("an example Valgrind tool"); 80 VG_(details_copyright_author)( 81 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote."); 82 VG_(details_bug_reports_to) (VG_BUGS_TO); 83 VG_(details_avg_translation_sizeB) ( 175 ); 84} 85 86void TL_(post_clo_init)(void) 87{ 88} 89 90/* Note: machine instructions are marked by an INCEIP at the end of each one, 91 except for the final one in the basic block which ends in an 92 unconditional JMP. Sometimes the final unconditional JMP is preceded by 93 a conditional JMP (Jcc), and thus it isn't reached. Eg: 94 95 <code a> 96 INCEIP ... 97 98 <code b> 99 Jcc ... 100 JMP ... (will not be reached if Jcc succeeds) 101 102 If we simplemindedly added calls to add_one_guest_instr() before INCEIPs 103 and unconditional JMPs, we'd sometimes miss the final call (when a 104 preceding conditional JMP succeeds), underestimating the machine instruction 105 count. 106 107 <code a> 108 call add_one_guest_instr() 109 INCEIP ... 110 111 <code b> 112 Jcc ... 113 call add_one_guest_instr() 114 JMP ... 115 116 Instead we add a call before each INCEIP, and also one at the start of the 117 block, but not one at the end, viz: 118 119 call add_one_guest_instr() 120 121 <code a> 122 call add_one_guest_instr() 123 INCEIP ... 124 125 <code b> 126 Jcc ... 127 JMP ... 128 129 Which gives us the right answer. And just to avoid two C calls, we fold 130 the basic-block-beginning call in with add_one_BB(). Phew. 131*/ 132IRBB* TL_(instrument)(IRBB* bb_in, VexGuestLayout* layout, IRType hWordTy ) 133{ 134 IRDirty* di; 135 Int i; 136 137 /* Set up BB */ 138 IRBB* bb = emptyIRBB(); 139 bb->tyenv = dopyIRTypeEnv(bb_in->tyenv); 140 bb->next = dopyIRExpr(bb_in->next); 141 bb->jumpkind = bb_in->jumpkind; 142 143#if 0 144 /* We need to know the entry point for this bb to do this. In any 145 case it's pretty meaningless in the presence of bb chasing since 146 we may enter this function part way through an IRBB. */ 147 /* Count call to dlrr(), if this BB is dlrr()'s entry point */ 148 if (VG_(get_fnname_if_entry)(orig_addr, fnname, 100) && 149 0 == VG_(strcmp)(fnname, "_dl_runtime_resolve")) 150 { 151 addStmtToIRBB( 152 bb, 153 IRStmt_Dirty( 154 unsafeIRDirty_0_N( "add_one_dlrr_call", mkIRExprVec_0() ) 155 )); 156 } 157#endif 158 159 /* Count this basic block */ 160 di = unsafeIRDirty_0_N( 0, "add_one_BB", &add_one_BB, mkIRExprVec_0() ); 161 addStmtToIRBB( bb, IRStmt_Dirty(di) ); 162 163 for (i = 0; i < bb_in->stmts_used; i++) { 164 IRStmt* st = bb_in->stmts[i]; 165 if (!st) continue; 166 167 switch (st->tag) { 168 case Ist_Exit: 169 /* Count Jcc */ 170 addStmtToIRBB( 171 bb, 172 IRStmt_Dirty( 173 unsafeIRDirty_0_N( 0, "add_one_Jcc", &add_one_Jcc, 174 mkIRExprVec_0() ) 175 )); 176 addStmtToIRBB( bb, dopyIRStmt(st) ); 177 /* Count non-taken Jcc */ 178 addStmtToIRBB( 179 bb, 180 IRStmt_Dirty( 181 unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken", &add_one_Jcc_untaken, 182 mkIRExprVec_0() ) 183 )); 184 break; 185 186 default: 187 addStmtToIRBB( bb, st ); 188 } 189 } 190 191 return bb; 192 193 194#if 0 195 UCodeBlock* cb; 196 Int i; 197 UInstr* u; 198 Char fnname[100]; 199 200 cb = VG_(setup_UCodeBlock)(cb_in); 201 202 /* Count basic block */ 203 VG_(call_helper_0_0)(cb, (Addr) & add_one_BB); 204 205 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) { 206 u = VG_(get_instr)(cb_in, i); 207 208 switch (u->opcode) { 209 case NOP: case LOCK: case CALLM_S: case CALLM_E: 210 break; 211 212 case INCEIP: 213 /* Count x86 instr */ 214 VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr); 215 VG_(copy_UInstr)(cb, u); 216 break; 217 218 case JMP: 219 if (u->cond != CondAlways) { 220 /* Count Jcc */ 221 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc); 222 VG_(copy_UInstr)(cb, u); 223 /* Count non-taken Jcc */ 224 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken); 225 } else { 226 VG_(copy_UInstr)(cb, u); 227 } 228 break; 229 230 default: 231 /* Count UInstr */ 232 VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr); 233 VG_(copy_UInstr)(cb, u); 234 break; 235 } 236 } 237 238 VG_(free_UCodeBlock)(cb_in); 239 return cb; 240#endif 241} 242 243void TL_(fini)(Int exitcode) 244{ 245 VG_(message)(Vg_UserMsg, 246 "Counted %d calls to _dl_runtime_resolve()", n_dlrr_calls); 247 248 VG_(message)(Vg_UserMsg, ""); 249 VG_(message)(Vg_UserMsg, "Executed:"); 250 VG_(message)(Vg_UserMsg, " BBs: %u", n_BBs); 251 VG_(message)(Vg_UserMsg, " guest instrs: %u", n_guest_instrs); 252 VG_(message)(Vg_UserMsg, " UInstrs: %u", n_UInstrs); 253 254 VG_(message)(Vg_UserMsg, ""); 255 VG_(message)(Vg_UserMsg, "Jccs:"); 256 VG_(message)(Vg_UserMsg, " total: %u", n_Jccs); 257 VG_(message)(Vg_UserMsg, " %% taken: %u%%", 258 (n_Jccs - n_Jccs_untaken)*100 / 259 (n_Jccs ? n_Jccs : 1)); 260 261 VG_(message)(Vg_UserMsg, ""); 262 VG_(message)(Vg_UserMsg, "Ratios:"); 263 VG_(message)(Vg_UserMsg, " guest instrs : BB = %3u : 10", 264 10 * n_guest_instrs / n_BBs); 265 VG_(message)(Vg_UserMsg, " UInstrs : BB = %3u : 10", 266 10 * n_UInstrs / n_BBs); 267 VG_(message)(Vg_UserMsg, " UInstrs : x86_instr = %3u : 10", 268 10 * n_UInstrs / n_guest_instrs); 269 270 VG_(message)(Vg_UserMsg, ""); 271 VG_(message)(Vg_UserMsg, "Exit code: %d", exitcode); 272} 273 274VG_DETERMINE_INTERFACE_VERSION(TL_(pre_clo_init), 0) 275 276 277/*--------------------------------------------------------------------*/ 278/*--- end lk_main.c ---*/ 279/*--------------------------------------------------------------------*/ 280 281