lk_main.c revision bb1c99123c95fb9a4a2617d6e1d09559ac68db80
1
2/*--------------------------------------------------------------------*/
3/*--- Simple tool for counting UInstrs, using a C helper.          ---*/
4/*---                                                    lk_main.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8   This file is part of Lackey, an example Valgrind tool that does
9   some simple program measurement.
10
11   Copyright (C) 2002-2004 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
34/* 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;
38static ULong n_x86_instrs   = 0;
39static 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
47/* See comment above SK_(instrument) for reason why n_x86_instrs is
48   incremented here. */
49static void add_one_BB(void)
50{
51   n_BBs++;
52   n_x86_instrs++;
53}
54
55static void add_one_UInstr(void)
56{
57   n_UInstrs++;
58}
59
60static void add_one_x86_instr(void)
61{
62   n_x86_instrs++;
63}
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
75void SK_(pre_clo_init)(void)
76{
77   VG_(details_name)            ("Lackey");
78   VG_(details_version)         (NULL);
79   VG_(details_description)     ("an example Valgrind tool");
80   VG_(details_copyright_author)(
81      "Copyright (C) 2002-2004, and GNU GPL'd, by Nicholas Nethercote.");
82   VG_(details_bug_reports_to)  (VG_BUGS_TO);
83   VG_(details_avg_translation_sizeB) ( 175 );
84
85   VG_(register_compact_helper)((Addr) & add_one_dlrr_call);
86   VG_(register_compact_helper)((Addr) & add_one_BB);
87   VG_(register_compact_helper)((Addr) & add_one_x86_instr);
88   VG_(register_compact_helper)((Addr) & add_one_UInstr);
89   VG_(register_compact_helper)((Addr) & add_one_Jcc);
90   VG_(register_compact_helper)((Addr) & add_one_Jcc_untaken);
91}
92
93void SK_(post_clo_init)(void)
94{
95}
96
97/* Note: x86 instructions are marked by an INCEIP at the end of each one,
98   except for the final one in the basic block which ends in an
99   unconditional JMP.  Sometimes the final unconditional JMP is preceded by
100   a conditional JMP (Jcc), and thus it isn't reached.  Eg:
101
102      <code a>
103      INCEIP ...
104
105      <code b>
106      Jcc ...
107      JMP ...     (will not be reached if Jcc succeeds)
108
109   If we simplemindedly added calls to add_one_x86_instr() before INCEIPs
110   and unconditional JMPs, we'd sometimes miss the final call (when a
111   preceding conditional JMP succeeds), underestimating the x86 instruction
112   count.
113
114      <code a>
115      call add_one_x86_instr()
116      INCEIP ...
117
118      <code b>
119      Jcc ...
120      call add_one_x86_instr()
121      JMP ...
122
123   Instead we add a call before each INCEIP, and also one at the start of the
124   block, but not one at the end, viz:
125
126      call add_one_x86_instr()
127
128      <code a>
129      call add_one_x86_instr()
130      INCEIP ...
131
132      <code b>
133      Jcc ...
134      JMP ...
135
136   Which gives us the right answer.  And just to avoid two C calls, we fold
137   the basic-block-beginning call in with add_one_BB().  Phew.
138*/
139UCodeBlock* SK_(instrument)(UCodeBlock* cb_in, Addr orig_addr)
140{
141   UCodeBlock* cb;
142   Int         i;
143   UInstr*     u;
144   Char        fnname[100];
145
146   cb = VG_(setup_UCodeBlock)(cb_in);
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   {
152      VG_(call_helper_0_0)(cb, (Addr) & add_one_dlrr_call);
153   }
154
155   /* Count basic block */
156   VG_(call_helper_0_0)(cb, (Addr) & add_one_BB);
157
158   for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
159      u = VG_(get_instr)(cb_in, i);
160
161      switch (u->opcode) {
162         case NOP: case LOCK: case CALLM_S: case CALLM_E:
163            break;
164
165         case INCEIP:
166            /* Count x86 instr */
167            VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr);
168            VG_(copy_UInstr)(cb, u);
169            break;
170
171         case JMP:
172            if (u->cond != CondAlways) {
173               /* Count Jcc */
174               VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc);
175               VG_(copy_UInstr)(cb, u);
176               /* Count non-taken Jcc */
177               VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken);
178            } else {
179               VG_(copy_UInstr)(cb, u);
180            }
181            break;
182
183         default:
184            /* Count UInstr */
185            VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr);
186            VG_(copy_UInstr)(cb, u);
187            break;
188      }
189   }
190
191   VG_(free_UCodeBlock)(cb_in);
192   return cb;
193}
194
195void SK_(fini)(Int exitcode)
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    VG_(message)(Vg_UserMsg, "");
222    VG_(message)(Vg_UserMsg, "Exit code:     %d", exitcode);
223}
224
225VG_DETERMINE_INTERFACE_VERSION(SK_(pre_clo_init), 0)
226
227
228/*--------------------------------------------------------------------*/
229/*--- end                                                lk_main.c ---*/
230/*--------------------------------------------------------------------*/
231
232