File: lk_main.c

package info (click to toggle)
valgrind 1%3A2.4.0-2
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 9,384 kB
  • ctags: 8,831
  • sloc: ansic: 67,990; sh: 4,364; perl: 1,833; makefile: 1,125; asm: 978; cpp: 101
file content (224 lines) | stat: -rw-r--r-- 6,695 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224

/*--------------------------------------------------------------------*/
/*--- Simple tool for counting UInstrs, using a C helper.          ---*/
/*---                                                    lk_main.c ---*/
/*--------------------------------------------------------------------*/

/*
   This file is part of Lackey, an example Valgrind tool that does
   some simple program measurement.

   Copyright (C) 2002-2005 Nicholas Nethercote
      njn25@cam.ac.uk

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307, USA.

   The GNU General Public License is contained in the file COPYING.
*/

#include "tool.h"

/* Nb: use ULongs because the numbers can get very big */
static ULong n_dlrr_calls   = 0;
static ULong n_BBs          = 0;
static ULong n_UInstrs      = 0;
static ULong n_machine_instrs   = 0;
static ULong n_Jccs         = 0;
static ULong n_Jccs_untaken = 0;

static void add_one_dlrr_call(void)
{
   n_dlrr_calls++;
}

/* See comment above SK_(instrument) for reason why n_machine_instrs is
   incremented here. */
static void add_one_BB(void)
{
   n_BBs++;
   n_machine_instrs++;
}

static void add_one_UInstr(void)
{
   n_UInstrs++;
}

static void add_one_machine_instr(void)
{
   n_machine_instrs++;
}

static void add_one_Jcc(void)
{
   n_Jccs++;
}

static void add_one_Jcc_untaken(void)
{
   n_Jccs_untaken++;
}

void SK_(pre_clo_init)(void)
{
   VG_(details_name)            ("Lackey");
   VG_(details_version)         (NULL);
   VG_(details_description)     ("an example Valgrind tool");
   VG_(details_copyright_author)(
      "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote.");
   VG_(details_bug_reports_to)  (VG_BUGS_TO);
   VG_(details_avg_translation_sizeB) ( 175 );
}

void SK_(post_clo_init)(void)
{
}

/* Note: machine instructions are marked by an INCEIP at the end of each one,
   except for the final one in the basic block which ends in an
   unconditional JMP.  Sometimes the final unconditional JMP is preceded by
   a conditional JMP (Jcc), and thus it isn't reached.  Eg:

      <code a>
      INCEIP ...

      <code b>
      Jcc ...
      JMP ...     (will not be reached if Jcc succeeds)

   If we simplemindedly added calls to add_one_machine_instr() before INCEIPs
   and unconditional JMPs, we'd sometimes miss the final call (when a
   preceding conditional JMP succeeds), underestimating the machine instruction
   count.

      <code a>
      call add_one_machine_instr()
      INCEIP ...

      <code b>
      Jcc ...
      call add_one_machine_instr()
      JMP ...

   Instead we add a call before each INCEIP, and also one at the start of the
   block, but not one at the end, viz:

      call add_one_machine_instr()

      <code a>
      call add_one_machine_instr()
      INCEIP ...

      <code b>
      Jcc ...
      JMP ...

   Which gives us the right answer.  And just to avoid two C calls, we fold
   the basic-block-beginning call in with add_one_BB().  Phew.
*/ 
UCodeBlock* SK_(instrument)(UCodeBlock* cb_in, Addr orig_addr)
{
   UCodeBlock* cb;
   Int         i;
   UInstr*     u;
   Char        fnname[100];

   cb = VG_(setup_UCodeBlock)(cb_in);

   /* Count call to dlrr(), if this BB is dlrr()'s entry point */
   if (VG_(get_fnname_if_entry)(orig_addr, fnname, 100) &&
       0 == VG_(strcmp)(fnname, "_dl_runtime_resolve")) 
   {
      VG_(call_helper_0_0)(cb, (Addr) & add_one_dlrr_call);
   }

   /* Count basic block */
   VG_(call_helper_0_0)(cb, (Addr) & add_one_BB);

   for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
      u = VG_(get_instr)(cb_in, i);

      switch (u->opcode) {
         case NOP: case LOCK: case CALLM_S: case CALLM_E:
            break;
   
         case INCEIP:
            /* Count machine instr */
            VG_(call_helper_0_0)(cb, (Addr) & add_one_machine_instr);
            VG_(copy_UInstr)(cb, u);
            break;

         case JMP:
            if (u->cond != CondAlways) {
               /* Count Jcc */
               VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc);
               VG_(copy_UInstr)(cb, u);
               /* Count non-taken Jcc */
               VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken);
            } else {
               VG_(copy_UInstr)(cb, u);
            }
            break;

         default:
            /* Count UInstr */
            VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr);
            VG_(copy_UInstr)(cb, u);
            break;
      }
   }

   VG_(free_UCodeBlock)(cb_in);
   return cb;
}

void SK_(fini)(Int exitcode)
{
    VG_(message)(Vg_UserMsg,
                 "Counted %d calls to _dl_runtime_resolve()", n_dlrr_calls);

    VG_(message)(Vg_UserMsg, "");
    VG_(message)(Vg_UserMsg, "Executed:");
    VG_(message)(Vg_UserMsg, "  BBs:             %llu", n_BBs);
    VG_(message)(Vg_UserMsg, "  machine instrs:  %llu", n_machine_instrs);
    VG_(message)(Vg_UserMsg, "  UInstrs:         %llu", n_UInstrs);

    VG_(message)(Vg_UserMsg, "");
    VG_(message)(Vg_UserMsg, "Jccs:");
    VG_(message)(Vg_UserMsg, "  total:           %llu", n_Jccs);
    VG_(message)(Vg_UserMsg, "  %% taken:         %llu%%",
                             (n_Jccs - n_Jccs_untaken)*100 / n_Jccs);

    VG_(message)(Vg_UserMsg, "");
    VG_(message)(Vg_UserMsg, "Ratios:");
    VG_(message)(Vg_UserMsg, "  machine instrs : BB            = %3llu : 10",
                             10 * n_machine_instrs / n_BBs);
    VG_(message)(Vg_UserMsg, "         UInstrs : BB            = %3llu : 10",
                             10 * n_UInstrs / n_BBs);
    VG_(message)(Vg_UserMsg, "         UInstrs : machine_instr = %3llu : 10",
                             10 * n_UInstrs / n_machine_instrs);

    VG_(message)(Vg_UserMsg, "");
    VG_(message)(Vg_UserMsg, "Exit code:     %d", exitcode);
}

VG_DETERMINE_INTERFACE_VERSION(SK_(pre_clo_init), 0)


/*--------------------------------------------------------------------*/
/*--- end                                                lk_main.c ---*/
/*--------------------------------------------------------------------*/