lk_main.c revision 0e1b514ab8e837f75a207a037ea53a6a721e9d28
1 2/*--------------------------------------------------------------------*/ 3/*--- Simple skin for counting UInstrs, using a C helper. ---*/ 4/*--- lk_main.c ---*/ 5/*--------------------------------------------------------------------*/ 6 7/* 8 This file is part of Lackey, an example Valgrind skin that does 9 some simple program measurement. 10 11 Copyright (C) 2002-2003 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 34VG_DETERMINE_INTERFACE_VERSION 35 36/* Nb: use ULongs because the numbers can get very big */ 37static ULong n_dlrr_calls = 0; 38static ULong n_BBs = 0; 39static ULong n_UInstrs = 0; 40static ULong n_x86_instrs = 0; 41static ULong n_Jccs = 0; 42static ULong n_Jccs_untaken = 0; 43 44static void add_one_dlrr_call(void) 45{ 46 n_dlrr_calls++; 47} 48 49/* See comment above SK_(instrument) for reason why n_x86_instrs is 50 incremented here. */ 51static void add_one_BB(void) 52{ 53 n_BBs++; 54 n_x86_instrs++; 55} 56 57static void add_one_UInstr(void) 58{ 59 n_UInstrs++; 60} 61 62static void add_one_x86_instr(void) 63{ 64 n_x86_instrs++; 65} 66 67static void add_one_Jcc(void) 68{ 69 n_Jccs++; 70} 71 72static void add_one_Jcc_untaken(void) 73{ 74 n_Jccs_untaken++; 75} 76 77void SK_(pre_clo_init)(void) 78{ 79 VG_(details_name) ("Lackey"); 80 VG_(details_version) (NULL); 81 VG_(details_description) ("an example Valgrind skin"); 82 VG_(details_copyright_author)( 83 "Copyright (C) 2002-2003, and GNU GPL'd, by Nicholas Nethercote."); 84 VG_(details_bug_reports_to) ("njn25@cam.ac.uk"); 85 VG_(details_avg_translation_sizeB) ( 175 ); 86 87 VG_(register_compact_helper)((Addr) & add_one_dlrr_call); 88 VG_(register_compact_helper)((Addr) & add_one_BB); 89 VG_(register_compact_helper)((Addr) & add_one_x86_instr); 90 VG_(register_compact_helper)((Addr) & add_one_UInstr); 91 VG_(register_compact_helper)((Addr) & add_one_Jcc); 92 VG_(register_compact_helper)((Addr) & add_one_Jcc_untaken); 93} 94 95void SK_(post_clo_init)(void) 96{ 97} 98 99/* Note: x86 instructions are marked by an INCEIP at the end of each one, 100 except for the final one in the basic block which ends in an 101 unconditional JMP. Sometimes the final unconditional JMP is preceded by 102 a conditional JMP (Jcc), and thus it isn't reached. Eg: 103 104 <code a> 105 INCEIP ... 106 107 <code b> 108 Jcc ... 109 JMP ... (will not be reached if Jcc succeeds) 110 111 If we simplemindedly added calls to add_one_x86_instr() before INCEIPs 112 and unconditional JMPs, we'd sometimes miss the final call (when a 113 preceding conditional JMP succeeds), underestimating the x86 instruction 114 count. 115 116 <code a> 117 call add_one_x86_instr() 118 INCEIP ... 119 120 <code b> 121 Jcc ... 122 call add_one_x86_instr() 123 JMP ... 124 125 Instead we add a call before each INCEIP, and also one at the start of the 126 block, but not one at the end, viz: 127 128 call add_one_x86_instr() 129 130 <code a> 131 call add_one_x86_instr() 132 INCEIP ... 133 134 <code b> 135 Jcc ... 136 JMP ... 137 138 Which gives us the right answer. And just to avoid two C calls, we fold 139 the basic-block-beginning call in with add_one_BB(). Phew. 140*/ 141UCodeBlock* SK_(instrument)(UCodeBlock* cb_in, Addr orig_addr) 142{ 143 UCodeBlock* cb; 144 Int i; 145 UInstr* u; 146 Char fnname[100]; 147 148 cb = VG_(setup_UCodeBlock)(cb_in); 149 150 /* Count call to dlrr(), if this BB is dlrr()'s entry point */ 151 if (VG_(get_fnname_if_entry)(orig_addr, fnname, 100) && 152 0 == VG_(strcmp)(fnname, "_dl_runtime_resolve")) 153 { 154 VG_(call_helper_0_0)(cb, (Addr) & add_one_dlrr_call); 155 } 156 157 /* Count basic block */ 158 VG_(call_helper_0_0)(cb, (Addr) & add_one_BB); 159 160 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) { 161 u = VG_(get_instr)(cb_in, i); 162 163 switch (u->opcode) { 164 case NOP: case LOCK: case CALLM_S: case CALLM_E: 165 break; 166 167 case INCEIP: 168 /* Count x86 instr */ 169 VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr); 170 VG_(copy_UInstr)(cb, u); 171 break; 172 173 case JMP: 174 if (u->cond != CondAlways) { 175 /* Count Jcc */ 176 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc); 177 VG_(copy_UInstr)(cb, u); 178 /* Count non-taken Jcc */ 179 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken); 180 } else { 181 VG_(copy_UInstr)(cb, u); 182 } 183 break; 184 185 case MMX1: case MMX2: case MMX3: 186 case MMX2_MemRd: case MMX2_MemWr: 187 case MMX2_RegRd: case MMX2_RegWr: 188 VG_(skin_panic)( 189 "I don't know how to instrument MMXish stuff (yet)"); 190 break; 191 192 default: 193 /* Count UInstr */ 194 VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr); 195 VG_(copy_UInstr)(cb, u); 196 break; 197 } 198 } 199 200 VG_(free_UCodeBlock)(cb_in); 201 return cb; 202} 203 204void SK_(fini)(void) 205{ 206 VG_(message)(Vg_UserMsg, 207 "Counted %d calls to _dl_runtime_resolve()", n_dlrr_calls); 208 209 VG_(message)(Vg_UserMsg, ""); 210 VG_(message)(Vg_UserMsg, "Executed:"); 211 VG_(message)(Vg_UserMsg, " BBs: %u", n_BBs); 212 VG_(message)(Vg_UserMsg, " x86 instrs: %u", n_x86_instrs); 213 VG_(message)(Vg_UserMsg, " UInstrs: %u", n_UInstrs); 214 215 VG_(message)(Vg_UserMsg, ""); 216 VG_(message)(Vg_UserMsg, "Jccs:"); 217 VG_(message)(Vg_UserMsg, " total: %u", n_Jccs); 218 VG_(message)(Vg_UserMsg, " %% taken: %u%%", 219 (n_Jccs - n_Jccs_untaken)*100 / n_Jccs); 220 221 VG_(message)(Vg_UserMsg, ""); 222 VG_(message)(Vg_UserMsg, "Ratios:"); 223 VG_(message)(Vg_UserMsg, " x86 instrs : BB = %3u : 10", 224 10 * n_x86_instrs / n_BBs); 225 VG_(message)(Vg_UserMsg, " UInstrs : BB = %3u : 10", 226 10 * n_UInstrs / n_BBs); 227 VG_(message)(Vg_UserMsg, " UInstrs : x86_instr = %3u : 10", 228 10 * n_UInstrs / n_x86_instrs); 229 230} 231 232/*--------------------------------------------------------------------*/ 233/*--- end lk_main.c ---*/ 234/*--------------------------------------------------------------------*/ 235 236