lk_main.c revision bb1c99123c95fb9a4a2617d6e1d09559ac68db80
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-2004 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 "vg_skin.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_x86_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 SK_(instrument) for reason why n_x86_instrs is 48 incremented here. */ 49static void add_one_BB(void) 50{ 51 n_BBs++; 52 n_x86_instrs++; 53} 54 55static void add_one_UInstr(void) 56{ 57 n_UInstrs++; 58} 59 60static void add_one_x86_instr(void) 61{ 62 n_x86_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 SK_(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-2004, 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 VG_(register_compact_helper)((Addr) & add_one_dlrr_call); 86 VG_(register_compact_helper)((Addr) & add_one_BB); 87 VG_(register_compact_helper)((Addr) & add_one_x86_instr); 88 VG_(register_compact_helper)((Addr) & add_one_UInstr); 89 VG_(register_compact_helper)((Addr) & add_one_Jcc); 90 VG_(register_compact_helper)((Addr) & add_one_Jcc_untaken); 91} 92 93void SK_(post_clo_init)(void) 94{ 95} 96 97/* Note: x86 instructions are marked by an INCEIP at the end of each one, 98 except for the final one in the basic block which ends in an 99 unconditional JMP. Sometimes the final unconditional JMP is preceded by 100 a conditional JMP (Jcc), and thus it isn't reached. Eg: 101 102 <code a> 103 INCEIP ... 104 105 <code b> 106 Jcc ... 107 JMP ... (will not be reached if Jcc succeeds) 108 109 If we simplemindedly added calls to add_one_x86_instr() before INCEIPs 110 and unconditional JMPs, we'd sometimes miss the final call (when a 111 preceding conditional JMP succeeds), underestimating the x86 instruction 112 count. 113 114 <code a> 115 call add_one_x86_instr() 116 INCEIP ... 117 118 <code b> 119 Jcc ... 120 call add_one_x86_instr() 121 JMP ... 122 123 Instead we add a call before each INCEIP, and also one at the start of the 124 block, but not one at the end, viz: 125 126 call add_one_x86_instr() 127 128 <code a> 129 call add_one_x86_instr() 130 INCEIP ... 131 132 <code b> 133 Jcc ... 134 JMP ... 135 136 Which gives us the right answer. And just to avoid two C calls, we fold 137 the basic-block-beginning call in with add_one_BB(). Phew. 138*/ 139UCodeBlock* SK_(instrument)(UCodeBlock* cb_in, Addr orig_addr) 140{ 141 UCodeBlock* cb; 142 Int i; 143 UInstr* u; 144 Char fnname[100]; 145 146 cb = VG_(setup_UCodeBlock)(cb_in); 147 148 /* Count call to dlrr(), if this BB is dlrr()'s entry point */ 149 if (VG_(get_fnname_if_entry)(orig_addr, fnname, 100) && 150 0 == VG_(strcmp)(fnname, "_dl_runtime_resolve")) 151 { 152 VG_(call_helper_0_0)(cb, (Addr) & add_one_dlrr_call); 153 } 154 155 /* Count basic block */ 156 VG_(call_helper_0_0)(cb, (Addr) & add_one_BB); 157 158 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) { 159 u = VG_(get_instr)(cb_in, i); 160 161 switch (u->opcode) { 162 case NOP: case LOCK: case CALLM_S: case CALLM_E: 163 break; 164 165 case INCEIP: 166 /* Count x86 instr */ 167 VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr); 168 VG_(copy_UInstr)(cb, u); 169 break; 170 171 case JMP: 172 if (u->cond != CondAlways) { 173 /* Count Jcc */ 174 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc); 175 VG_(copy_UInstr)(cb, u); 176 /* Count non-taken Jcc */ 177 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken); 178 } else { 179 VG_(copy_UInstr)(cb, u); 180 } 181 break; 182 183 default: 184 /* Count UInstr */ 185 VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr); 186 VG_(copy_UInstr)(cb, u); 187 break; 188 } 189 } 190 191 VG_(free_UCodeBlock)(cb_in); 192 return cb; 193} 194 195void SK_(fini)(Int exitcode) 196{ 197 VG_(message)(Vg_UserMsg, 198 "Counted %d calls to _dl_runtime_resolve()", n_dlrr_calls); 199 200 VG_(message)(Vg_UserMsg, ""); 201 VG_(message)(Vg_UserMsg, "Executed:"); 202 VG_(message)(Vg_UserMsg, " BBs: %u", n_BBs); 203 VG_(message)(Vg_UserMsg, " x86 instrs: %u", n_x86_instrs); 204 VG_(message)(Vg_UserMsg, " UInstrs: %u", n_UInstrs); 205 206 VG_(message)(Vg_UserMsg, ""); 207 VG_(message)(Vg_UserMsg, "Jccs:"); 208 VG_(message)(Vg_UserMsg, " total: %u", n_Jccs); 209 VG_(message)(Vg_UserMsg, " %% taken: %u%%", 210 (n_Jccs - n_Jccs_untaken)*100 / n_Jccs); 211 212 VG_(message)(Vg_UserMsg, ""); 213 VG_(message)(Vg_UserMsg, "Ratios:"); 214 VG_(message)(Vg_UserMsg, " x86 instrs : BB = %3u : 10", 215 10 * n_x86_instrs / n_BBs); 216 VG_(message)(Vg_UserMsg, " UInstrs : BB = %3u : 10", 217 10 * n_UInstrs / n_BBs); 218 VG_(message)(Vg_UserMsg, " UInstrs : x86_instr = %3u : 10", 219 10 * n_UInstrs / n_x86_instrs); 220 221 VG_(message)(Vg_UserMsg, ""); 222 VG_(message)(Vg_UserMsg, "Exit code: %d", exitcode); 223} 224 225VG_DETERMINE_INTERFACE_VERSION(SK_(pre_clo_init), 0) 226 227 228/*--------------------------------------------------------------------*/ 229/*--- end lk_main.c ---*/ 230/*--------------------------------------------------------------------*/ 231 232