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