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