lk_main.c revision 51d827bcd88ce045a383ea1ca81768757df2d1fa
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-2005 Nicholas Nethercote
12      njn@valgrind.org
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 "tool.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_guest_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 lk_instrument for reason why n_machine_instrs is
48   incremented here. */
49static void add_one_BB(void)
50{
51   n_BBs++;
52   n_guest_instrs++;
53}
54
55static void add_one_UInstr(void)
56{
57   n_UInstrs++;
58}
59
60static void add_one_guest_instr(void)
61{
62   n_guest_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
75static void lk_post_clo_init(void)
76{
77}
78
79/* Note: machine instructions are marked by an INCEIP at the end of each one,
80   except for the final one in the basic block which ends in an
81   unconditional JMP.  Sometimes the final unconditional JMP is preceded by
82   a conditional JMP (Jcc), and thus it isn't reached.  Eg:
83
84      <code a>
85      INCEIP ...
86
87      <code b>
88      Jcc ...
89      JMP ...     (will not be reached if Jcc succeeds)
90
91   If we simplemindedly added calls to add_one_guest_instr() before INCEIPs
92   and unconditional JMPs, we'd sometimes miss the final call (when a
93   preceding conditional JMP succeeds), underestimating the machine instruction
94   count.
95
96      <code a>
97      call add_one_guest_instr()
98      INCEIP ...
99
100      <code b>
101      Jcc ...
102      call add_one_guest_instr()
103      JMP ...
104
105   Instead we add a call before each INCEIP, and also one at the start of the
106   block, but not one at the end, viz:
107
108      call add_one_guest_instr()
109
110      <code a>
111      call add_one_guest_instr()
112      INCEIP ...
113
114      <code b>
115      Jcc ...
116      JMP ...
117
118   Which gives us the right answer.  And just to avoid two C calls, we fold
119   the basic-block-beginning call in with add_one_BB().  Phew.
120*/
121static IRBB* lk_instrument(IRBB* bb_in, VexGuestLayout* layout,
122                           IRType gWordTy, IRType hWordTy )
123{
124   IRDirty* di;
125   Int      i;
126   IRBB*    bb;
127
128   if (gWordTy != hWordTy) {
129      /* We don't currently support this case. */
130      VG_(tool_panic)("host/guest word size mismatch");
131   }
132
133   /* Set up BB */
134   bb           = emptyIRBB();
135   bb->tyenv    = dopyIRTypeEnv(bb_in->tyenv);
136   bb->next     = dopyIRExpr(bb_in->next);
137   bb->jumpkind = bb_in->jumpkind;
138
139#if 0
140   /* We need to know the entry point for this bb to do this.  In any
141      case it's pretty meaningless in the presence of bb chasing since
142      we may enter this function part way through an IRBB. */
143   /* Count call to dlrr(), if this BB is dlrr()'s entry point */
144   if (VG_(get_fnname_if_entry)(orig_addr, fnname, 100) &&
145       0 == VG_(strcmp)(fnname, "_dl_runtime_resolve"))
146   {
147      addStmtToIRBB(
148         bb,
149         IRStmt_Dirty(
150            unsafeIRDirty_0_N( "add_one_dlrr_call", mkIRExprVec_0() )
151      ));
152   }
153#endif
154
155   /* Count this basic block */
156   di = unsafeIRDirty_0_N( 0, "add_one_BB", &add_one_BB, mkIRExprVec_0() );
157   addStmtToIRBB( bb, IRStmt_Dirty(di) );
158
159   for (i = 0; i < bb_in->stmts_used; i++) {
160      IRStmt* st = bb_in->stmts[i];
161      if (!st) continue;
162
163      switch (st->tag) {
164         case Ist_Exit:
165            /* Count Jcc */
166            addStmtToIRBB(
167               bb,
168               IRStmt_Dirty(
169                  unsafeIRDirty_0_N( 0, "add_one_Jcc", &add_one_Jcc,
170                                        mkIRExprVec_0() )
171            ));
172            addStmtToIRBB( bb, dopyIRStmt(st) );
173            /* Count non-taken Jcc */
174            addStmtToIRBB(
175               bb,
176               IRStmt_Dirty(
177                  unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken", &add_one_Jcc_untaken,
178                                        mkIRExprVec_0() )
179            ));
180            break;
181
182         default:
183            addStmtToIRBB( bb, st );
184      }
185   }
186
187   return bb;
188
189
190#if 0
191   UCodeBlock* cb;
192   Int         i;
193   UInstr*     u;
194   Char        fnname[100];
195
196   cb = VG_(setup_UCodeBlock)(cb_in);
197
198   /* Count basic block */
199   VG_(call_helper_0_0)(cb, (Addr) & add_one_BB);
200
201   for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
202      u = VG_(get_instr)(cb_in, i);
203
204      switch (u->opcode) {
205         case NOP: case LOCK: case CALLM_S: case CALLM_E:
206            break;
207
208         case INCEIP:
209            /* Count x86 instr */
210            VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr);
211            VG_(copy_UInstr)(cb, u);
212            break;
213
214         case JMP:
215            if (u->cond != CondAlways) {
216               /* Count Jcc */
217               VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc);
218               VG_(copy_UInstr)(cb, u);
219               /* Count non-taken Jcc */
220               VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken);
221            } else {
222               VG_(copy_UInstr)(cb, u);
223            }
224            break;
225
226         default:
227            /* Count UInstr */
228            VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr);
229            VG_(copy_UInstr)(cb, u);
230            break;
231      }
232   }
233
234   VG_(free_UCodeBlock)(cb_in);
235   return cb;
236#endif
237}
238
239static void lk_fini(Int exitcode)
240{
241    VG_(message)(Vg_UserMsg,
242                 "Counted %d calls to _dl_runtime_resolve()", n_dlrr_calls);
243
244    VG_(message)(Vg_UserMsg, "");
245    VG_(message)(Vg_UserMsg, "Executed:");
246    VG_(message)(Vg_UserMsg, "  BBs:          %u", n_BBs);
247    VG_(message)(Vg_UserMsg, "  guest instrs: %u", n_guest_instrs);
248    VG_(message)(Vg_UserMsg, "  UInstrs:      %u", n_UInstrs);
249
250    VG_(message)(Vg_UserMsg, "");
251    VG_(message)(Vg_UserMsg, "Jccs:");
252    VG_(message)(Vg_UserMsg, "  total:       %u", n_Jccs);
253    VG_(message)(Vg_UserMsg, "  %% taken:     %u%%",
254                             (n_Jccs - n_Jccs_untaken)*100 /
255                             (n_Jccs ? n_Jccs : 1));
256
257    VG_(message)(Vg_UserMsg, "");
258    VG_(message)(Vg_UserMsg, "Ratios:");
259    VG_(message)(Vg_UserMsg, "  guest instrs : BB      = %3u : 10",
260                             10 * n_guest_instrs / n_BBs);
261    VG_(message)(Vg_UserMsg, "     UInstrs : BB        = %3u : 10",
262                             10 * n_UInstrs / n_BBs);
263    VG_(message)(Vg_UserMsg, "     UInstrs : x86_instr = %3u : 10",
264                             10 * n_UInstrs / n_guest_instrs);
265
266    VG_(message)(Vg_UserMsg, "");
267    VG_(message)(Vg_UserMsg, "Exit code:     %d", exitcode);
268}
269
270static void lk_pre_clo_init(void)
271{
272   VG_(details_name)            ("Lackey");
273   VG_(details_version)         (NULL);
274   VG_(details_description)     ("an example Valgrind tool");
275   VG_(details_copyright_author)(
276      "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote.");
277   VG_(details_bug_reports_to)  (VG_BUGS_TO);
278   VG_(details_avg_translation_sizeB) ( 175 );
279
280   VG_(basic_tool_funcs)          (lk_post_clo_init,
281                                   lk_instrument,
282                                   lk_fini);
283}
284
285VG_DETERMINE_INTERFACE_VERSION(lk_pre_clo_init, 0)
286
287/*--------------------------------------------------------------------*/
288/*--- end                                                lk_main.c ---*/
289/*--------------------------------------------------------------------*/
290
291