blob: 95015d306d321fcba056a1d2100c937bac8198cf [file] [log] [blame]
njnc9539842002-10-02 13:26:35 +00001
njn25e49d8e72002-09-23 09:36:25 +00002/*--------------------------------------------------------------------*/
3/*--- Simple skin 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/*
njnc9539842002-10-02 13:26:35 +00008 This file is part of Lackey, an example Valgrind skin that does
9 some simple program measurement.
njn25e49d8e72002-09-23 09:36:25 +000010
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
njn4ba5a792002-09-30 10:23:54 +000034//#define uInstr0 VG_(new_UInstr0)
35//#define uLiteral VG_(set_lit_field)
njn25e49d8e72002-09-23 09:36:25 +000036
37/* Nb: use ULongs because the numbers can get very big */
38static ULong n_dlrr_calls = 0;
39static ULong n_BBs = 0;
40static ULong n_UInstrs = 0;
41static ULong n_x86_instrs = 0;
42static ULong n_Jccs = 0;
43static ULong n_Jccs_untaken = 0;
44
45static void add_one_dlrr_call(void)
46{
47 n_dlrr_calls++;
48}
49
50/* See comment above SK_(instrument) for reason why n_x86_instrs is
51 incremented here. */
52static void add_one_BB(void)
53{
54 n_BBs++;
55 n_x86_instrs++;
56}
57
58static void add_one_UInstr(void)
59{
60 n_UInstrs++;
61}
62
63static void add_one_x86_instr(void)
64{
65 n_x86_instrs++;
66}
67
68static void add_one_Jcc(void)
69{
70 n_Jccs++;
71}
72
73static void add_one_Jcc_untaken(void)
74{
75 n_Jccs_untaken++;
76}
77
78void SK_(pre_clo_init)(VgNeeds* needs, VgTrackEvents* not_used)
79{
80 needs->name = "lackey";
81 needs->description = "a UInstr counter";
njne427a662002-10-02 11:08:25 +000082 needs->description = "njn25@cam.ac.uk";
njn25e49d8e72002-09-23 09:36:25 +000083
njn25cac76cb2002-09-23 11:21:57 +000084 VG_(register_compact_helper)((Addr) & add_one_dlrr_call);
njn25e49d8e72002-09-23 09:36:25 +000085 VG_(register_compact_helper)((Addr) & add_one_BB);
86 VG_(register_compact_helper)((Addr) & add_one_x86_instr);
87 VG_(register_compact_helper)((Addr) & add_one_UInstr);
88 VG_(register_compact_helper)((Addr) & add_one_Jcc);
89 VG_(register_compact_helper)((Addr) & add_one_Jcc_untaken);
90}
91
92void SK_(post_clo_init)(void)
93{
94}
95
96/* Note: x86 instructions are marked by an INCEIP at the end of each one,
97 except for the final one in the basic block which ends in an
98 unconditional JMP. Sometimes the final unconditional JMP is preceded by
99 a conditional JMP (Jcc), and thus it isn't reached. Eg:
100
101 <code a>
102 INCEIP ...
103
104 <code b>
105 Jcc ...
106 JMP ... (will not be reached if Jcc succeeds)
107
108 If we simplemindedly added calls to add_one_x86_instr() before INCEIPs
109 and unconditional JMPs, we'd sometimes miss the final call (when a
110 preceding conditional JMP succeeds), underestimating the x86 instruction
111 count.
112
113 <code a>
114 call add_one_x86_instr()
115 INCEIP ...
116
117 <code b>
118 Jcc ...
119 call add_one_x86_instr()
120 JMP ...
121
122 Instead we add a call before each INCEIP, and also one at the start of the
123 block, but not one at the end, viz:
124
125 call add_one_x86_instr()
126
127 <code a>
128 call add_one_x86_instr()
129 INCEIP ...
130
131 <code b>
132 Jcc ...
133 JMP ...
134
135 Which gives us the right answer. And just to avoid two C calls, we fold
136 the basic-block-beginning call in with add_one_BB(). Phew.
137*/
138UCodeBlock* SK_(instrument)(UCodeBlock* cb_in, Addr orig_addr)
139{
140 UCodeBlock* cb;
141 Int i;
142 UInstr* u;
143 Char fnname[100];
144
njn4ba5a792002-09-30 10:23:54 +0000145 cb = VG_(alloc_UCodeBlock)();
njn25e49d8e72002-09-23 09:36:25 +0000146 cb->nextTemp = cb_in->nextTemp;
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 {
njn4ba5a792002-09-30 10:23:54 +0000152 VG_(call_helper_0_0)(cb, (Addr) & add_one_dlrr_call);
njn25e49d8e72002-09-23 09:36:25 +0000153 }
154
155 /* Count basic block */
njn4ba5a792002-09-30 10:23:54 +0000156 VG_(call_helper_0_0)(cb, (Addr) & add_one_BB);
njn25e49d8e72002-09-23 09:36:25 +0000157
158 for (i = 0; i < cb_in->used; i++) {
159 u = &cb_in->instrs[i];
160
161 switch (u->opcode) {
162 case NOP: case CALLM_S: case CALLM_E:
163 break;
164
165 case INCEIP:
166 /* Count x86 instr */
njn4ba5a792002-09-30 10:23:54 +0000167 VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr);
168 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000169 break;
170
171 case JMP:
172 if (u->cond != CondAlways) {
173 /* Count Jcc */
njn4ba5a792002-09-30 10:23:54 +0000174 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc);
175 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000176 /* Count non-taken Jcc */
njn4ba5a792002-09-30 10:23:54 +0000177 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken);
njn25e49d8e72002-09-23 09:36:25 +0000178 } else {
njn4ba5a792002-09-30 10:23:54 +0000179 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000180 }
181 break;
182
183 default:
184 /* Count UInstr */
njn4ba5a792002-09-30 10:23:54 +0000185 VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr);
186 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000187 break;
188 }
189 }
190
njn4ba5a792002-09-30 10:23:54 +0000191 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +0000192 return cb;
193}
194
195void SK_(fini)(void)
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}
222
223/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000224/*--- end lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +0000225/*--------------------------------------------------------------------*/
226