lk_main.c revision 27f1a386dce7eb9e1d30b841771c71f0de27f34f
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 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)(VgDetails* details, VgNeeds* not_used1, 78 VgTrackEvents* not_used2) 79{ 80 details->name = "Lackey"; 81 details->version = NULL; 82 details->description = "an example Valgrind skin"; 83 details->copyright_author = 84 "Copyright (C) 2002, and GNU GPL'd, by Nicholas Nethercote."; 85 details->bug_reports_to = "njn25@cam.ac.uk"; 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_(alloc_UCodeBlock)(); 149 cb->nextTemp = cb_in->nextTemp; 150 151 /* Count call to dlrr(), if this BB is dlrr()'s entry point */ 152 if (VG_(get_fnname_if_entry)(orig_addr, fnname, 100) && 153 0 == VG_(strcmp)(fnname, "_dl_runtime_resolve")) 154 { 155 VG_(call_helper_0_0)(cb, (Addr) & add_one_dlrr_call); 156 } 157 158 /* Count basic block */ 159 VG_(call_helper_0_0)(cb, (Addr) & add_one_BB); 160 161 for (i = 0; i < cb_in->used; i++) { 162 u = &cb_in->instrs[i]; 163 164 switch (u->opcode) { 165 case NOP: case CALLM_S: case CALLM_E: 166 break; 167 168 case INCEIP: 169 /* Count x86 instr */ 170 VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr); 171 VG_(copy_UInstr)(cb, u); 172 break; 173 174 case JMP: 175 if (u->cond != CondAlways) { 176 /* Count Jcc */ 177 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc); 178 VG_(copy_UInstr)(cb, u); 179 /* Count non-taken Jcc */ 180 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken); 181 } else { 182 VG_(copy_UInstr)(cb, u); 183 } 184 break; 185 186 default: 187 /* Count UInstr */ 188 VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr); 189 VG_(copy_UInstr)(cb, u); 190 break; 191 } 192 } 193 194 VG_(free_UCodeBlock)(cb_in); 195 return cb; 196} 197 198void SK_(fini)(void) 199{ 200 VG_(message)(Vg_UserMsg, 201 "Counted %d calls to _dl_runtime_resolve()", n_dlrr_calls); 202 203 VG_(message)(Vg_UserMsg, ""); 204 VG_(message)(Vg_UserMsg, "Executed:"); 205 VG_(message)(Vg_UserMsg, " BBs: %u", n_BBs); 206 VG_(message)(Vg_UserMsg, " x86 instrs: %u", n_x86_instrs); 207 VG_(message)(Vg_UserMsg, " UInstrs: %u", n_UInstrs); 208 209 VG_(message)(Vg_UserMsg, ""); 210 VG_(message)(Vg_UserMsg, "Jccs:"); 211 VG_(message)(Vg_UserMsg, " total: %u", n_Jccs); 212 VG_(message)(Vg_UserMsg, " %% taken: %u%%", 213 (n_Jccs - n_Jccs_untaken)*100 / n_Jccs); 214 215 VG_(message)(Vg_UserMsg, ""); 216 VG_(message)(Vg_UserMsg, "Ratios:"); 217 VG_(message)(Vg_UserMsg, " x86 instrs : BB = %3u : 10", 218 10 * n_x86_instrs / n_BBs); 219 VG_(message)(Vg_UserMsg, " UInstrs : BB = %3u : 10", 220 10 * n_UInstrs / n_BBs); 221 VG_(message)(Vg_UserMsg, " UInstrs : x86_instr = %3u : 10", 222 10 * n_UInstrs / n_x86_instrs); 223 224} 225 226/*--------------------------------------------------------------------*/ 227/*--- end lk_main.c ---*/ 228/*--------------------------------------------------------------------*/ 229 230