blob: 4b79d9a1e6d992b9055ae43182788cc9c74a42cf [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
njn27f1a382002-11-08 15:48:16 +000034VG_DETERMINE_INTERFACE_VERSION
35
njn25e49d8e72002-09-23 09:36:25 +000036/* 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
njnd04b7c62002-10-03 14:05:52 +000077void SK_(pre_clo_init)(VgDetails* details, VgNeeds* not_used1,
78 VgTrackEvents* not_used2)
njn25e49d8e72002-09-23 09:36:25 +000079{
sewardj4aa62ba2002-10-05 15:49:27 +000080 details->name = "Lackey";
njnd04b7c62002-10-03 14:05:52 +000081 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";
njn25e49d8e72002-09-23 09:36:25 +000086
njn25cac76cb2002-09-23 11:21:57 +000087 VG_(register_compact_helper)((Addr) & add_one_dlrr_call);
njn25e49d8e72002-09-23 09:36:25 +000088 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
njn4ba5a792002-09-30 10:23:54 +0000148 cb = VG_(alloc_UCodeBlock)();
njn25e49d8e72002-09-23 09:36:25 +0000149 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 {
njn4ba5a792002-09-30 10:23:54 +0000155 VG_(call_helper_0_0)(cb, (Addr) & add_one_dlrr_call);
njn25e49d8e72002-09-23 09:36:25 +0000156 }
157
158 /* Count basic block */
njn4ba5a792002-09-30 10:23:54 +0000159 VG_(call_helper_0_0)(cb, (Addr) & add_one_BB);
njn25e49d8e72002-09-23 09:36:25 +0000160
161 for (i = 0; i < cb_in->used; i++) {
162 u = &cb_in->instrs[i];
163
164 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +0000165 case NOP: case LOCK: case CALLM_S: case CALLM_E:
njn25e49d8e72002-09-23 09:36:25 +0000166 break;
167
168 case INCEIP:
169 /* Count x86 instr */
njn4ba5a792002-09-30 10:23:54 +0000170 VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr);
171 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000172 break;
173
174 case JMP:
175 if (u->cond != CondAlways) {
176 /* Count Jcc */
njn4ba5a792002-09-30 10:23:54 +0000177 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc);
178 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000179 /* Count non-taken Jcc */
njn4ba5a792002-09-30 10:23:54 +0000180 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken);
njn25e49d8e72002-09-23 09:36:25 +0000181 } else {
njn4ba5a792002-09-30 10:23:54 +0000182 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000183 }
184 break;
185
186 default:
187 /* Count UInstr */
njn4ba5a792002-09-30 10:23:54 +0000188 VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr);
189 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000190 break;
191 }
192 }
193
njn4ba5a792002-09-30 10:23:54 +0000194 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +0000195 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/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000227/*--- end lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +0000228/*--------------------------------------------------------------------*/
229