blob: 18e6b115d96ecbe08a29d6fd540e69bf53b98535 [file] [log] [blame]
njnc9539842002-10-02 13:26:35 +00001
njn25e49d8e72002-09-23 09:36:25 +00002/*--------------------------------------------------------------------*/
nethercote137bc552003-11-14 17:47:54 +00003/*--- Simple tool for counting UInstrs, using a C helper. ---*/
njn25cac76cb2002-09-23 11:21:57 +00004/*--- lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00005/*--------------------------------------------------------------------*/
6
7/*
nethercote137bc552003-11-14 17:47:54 +00008 This file is part of Lackey, an example Valgrind tool that does
njnc9539842002-10-02 13:26:35 +00009 some simple program measurement.
njn25e49d8e72002-09-23 09:36:25 +000010
nethercotebb1c9912004-01-04 16:43:23 +000011 Copyright (C) 2002-2004 Nicholas Nethercote
njn25e49d8e72002-09-23 09:36:25 +000012 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
nethercote46063202004-09-02 08:51:43 +000032#include "tool.h"
njn25e49d8e72002-09-23 09:36:25 +000033
njn25e49d8e72002-09-23 09:36:25 +000034/* 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;
sewardj9f649aa2004-11-22 20:38:40 +000038static ULong n_guest_instrs = 0;
njn25e49d8e72002-09-23 09:36:25 +000039static 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
njn26f02512004-11-22 18:33:15 +000047/* See comment above TL_(instrument) for reason why n_machine_instrs is
njn25e49d8e72002-09-23 09:36:25 +000048 incremented here. */
49static void add_one_BB(void)
50{
51 n_BBs++;
sewardj9f649aa2004-11-22 20:38:40 +000052 n_guest_instrs++;
njn25e49d8e72002-09-23 09:36:25 +000053}
54
55static void add_one_UInstr(void)
56{
57 n_UInstrs++;
58}
59
sewardj9f649aa2004-11-22 20:38:40 +000060static void add_one_guest_instr(void)
njn25e49d8e72002-09-23 09:36:25 +000061{
sewardj9f649aa2004-11-22 20:38:40 +000062 n_guest_instrs++;
njn25e49d8e72002-09-23 09:36:25 +000063}
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
njn26f02512004-11-22 18:33:15 +000075void TL_(pre_clo_init)(void)
njn25e49d8e72002-09-23 09:36:25 +000076{
njn810086f2002-11-14 12:42:47 +000077 VG_(details_name) ("Lackey");
78 VG_(details_version) (NULL);
nethercote137bc552003-11-14 17:47:54 +000079 VG_(details_description) ("an example Valgrind tool");
njn810086f2002-11-14 12:42:47 +000080 VG_(details_copyright_author)(
nethercotebb1c9912004-01-04 16:43:23 +000081 "Copyright (C) 2002-2004, and GNU GPL'd, by Nicholas Nethercote.");
nethercote421281e2003-11-20 16:20:55 +000082 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardjc0d8f682002-11-30 00:49:43 +000083 VG_(details_avg_translation_sizeB) ( 175 );
njn25e49d8e72002-09-23 09:36:25 +000084}
85
njn26f02512004-11-22 18:33:15 +000086void TL_(post_clo_init)(void)
njn25e49d8e72002-09-23 09:36:25 +000087{
88}
89
nethercote7e08f062004-10-20 10:37:00 +000090/* Note: machine instructions are marked by an INCEIP at the end of each one,
njn25e49d8e72002-09-23 09:36:25 +000091 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
sewardj9f649aa2004-11-22 20:38:40 +0000102 If we simplemindedly added calls to add_one_guest_instr() before INCEIPs
njn25e49d8e72002-09-23 09:36:25 +0000103 and unconditional JMPs, we'd sometimes miss the final call (when a
nethercote7e08f062004-10-20 10:37:00 +0000104 preceding conditional JMP succeeds), underestimating the machine instruction
njn25e49d8e72002-09-23 09:36:25 +0000105 count.
106
107 <code a>
sewardj9f649aa2004-11-22 20:38:40 +0000108 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000109 INCEIP ...
110
111 <code b>
112 Jcc ...
sewardj9f649aa2004-11-22 20:38:40 +0000113 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000114 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
sewardj9f649aa2004-11-22 20:38:40 +0000119 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000120
121 <code a>
sewardj9f649aa2004-11-22 20:38:40 +0000122 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000123 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*/
sewardj9f649aa2004-11-22 20:38:40 +0000132IRBB* TL_(instrument)(IRBB* bb_in, VexGuestLayout* layout, IRType hWordTy )
njn25e49d8e72002-09-23 09:36:25 +0000133{
sewardj9f649aa2004-11-22 20:38:40 +0000134 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, dopyIRStmt(st));
188 }
189 }
190
191 return bb;
192
193
194#if 0
njn25e49d8e72002-09-23 09:36:25 +0000195 UCodeBlock* cb;
196 Int i;
197 UInstr* u;
198 Char fnname[100];
199
njn810086f2002-11-14 12:42:47 +0000200 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +0000201
njn25e49d8e72002-09-23 09:36:25 +0000202 /* Count basic block */
njn4ba5a792002-09-30 10:23:54 +0000203 VG_(call_helper_0_0)(cb, (Addr) & add_one_BB);
njn25e49d8e72002-09-23 09:36:25 +0000204
njn810086f2002-11-14 12:42:47 +0000205 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
206 u = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +0000207
208 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +0000209 case NOP: case LOCK: case CALLM_S: case CALLM_E:
njn25e49d8e72002-09-23 09:36:25 +0000210 break;
211
212 case INCEIP:
sewardj9f649aa2004-11-22 20:38:40 +0000213 /* Count x86 instr */
214 VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr);
njn4ba5a792002-09-30 10:23:54 +0000215 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000216 break;
217
218 case JMP:
219 if (u->cond != CondAlways) {
220 /* Count Jcc */
njn4ba5a792002-09-30 10:23:54 +0000221 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc);
222 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000223 /* Count non-taken Jcc */
njn4ba5a792002-09-30 10:23:54 +0000224 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken);
njn25e49d8e72002-09-23 09:36:25 +0000225 } else {
njn4ba5a792002-09-30 10:23:54 +0000226 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000227 }
228 break;
sewardj3d7c9c82003-03-26 21:08:13 +0000229
njn25e49d8e72002-09-23 09:36:25 +0000230 default:
231 /* Count UInstr */
njn4ba5a792002-09-30 10:23:54 +0000232 VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr);
233 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000234 break;
235 }
236 }
237
njn4ba5a792002-09-30 10:23:54 +0000238 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +0000239 return cb;
sewardj9f649aa2004-11-22 20:38:40 +0000240#endif
njn25e49d8e72002-09-23 09:36:25 +0000241}
242
njn26f02512004-11-22 18:33:15 +0000243void TL_(fini)(Int exitcode)
njn25e49d8e72002-09-23 09:36:25 +0000244{
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:");
sewardj9f649aa2004-11-22 20:38:40 +0000250 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);
njn25e49d8e72002-09-23 09:36:25 +0000253
254 VG_(message)(Vg_UserMsg, "");
255 VG_(message)(Vg_UserMsg, "Jccs:");
sewardj9f649aa2004-11-22 20:38:40 +0000256 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));
njn25e49d8e72002-09-23 09:36:25 +0000260
261 VG_(message)(Vg_UserMsg, "");
262 VG_(message)(Vg_UserMsg, "Ratios:");
sewardj9f649aa2004-11-22 20:38:40 +0000263 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",
njn25e49d8e72002-09-23 09:36:25 +0000266 10 * n_UInstrs / n_BBs);
sewardj9f649aa2004-11-22 20:38:40 +0000267 VG_(message)(Vg_UserMsg, " UInstrs : x86_instr = %3u : 10",
268 10 * n_UInstrs / n_guest_instrs);
njn25e49d8e72002-09-23 09:36:25 +0000269
njn7d9f94d2003-04-22 21:41:40 +0000270 VG_(message)(Vg_UserMsg, "");
271 VG_(message)(Vg_UserMsg, "Exit code: %d", exitcode);
njn25e49d8e72002-09-23 09:36:25 +0000272}
273
njn26f02512004-11-22 18:33:15 +0000274VG_DETERMINE_INTERFACE_VERSION(TL_(pre_clo_init), 0)
fitzhardinge98abfc72003-12-16 02:05:15 +0000275
276
njn25e49d8e72002-09-23 09:36:25 +0000277/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000278/*--- end lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +0000279/*--------------------------------------------------------------------*/
280