blob: 4aa3ce7e2ab53bb26ee07831e63e7ec117d2410d [file] [log] [blame]
weidendoa17f2a32006-03-20 10:27:30 +00001
2/*--------------------------------------------------------------------*/
3/*--- Callgrind ---*/
4/*--- main.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8 This file is part of Callgrind, a Valgrind tool for call graph
9 profiling programs.
10
sewardj9eecbbb2010-05-03 21:37:12 +000011 Copyright (C) 2002-2010, Josef Weidendorfer (Josef.Weidendorfer@gmx.de)
weidendoa17f2a32006-03-20 10:27:30 +000012
njn9a0cba42007-04-15 22:15:57 +000013 This tool is derived from and contains code from Cachegrind
sewardj9eecbbb2010-05-03 21:37:12 +000014 Copyright (C) 2002-2010 Nicholas Nethercote (njn@valgrind.org)
weidendoa17f2a32006-03-20 10:27:30 +000015
16 This program is free software; you can redistribute it and/or
17 modify it under the terms of the GNU General Public License as
18 published by the Free Software Foundation; either version 2 of the
19 License, or (at your option) any later version.
20
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29 02111-1307, USA.
30
31 The GNU General Public License is contained in the file COPYING.
32*/
33
34#include "config.h"
35#include "callgrind.h"
36#include "global.h"
37
38#include <pub_tool_threadstate.h>
39
40/*------------------------------------------------------------*/
41/*--- Global variables ---*/
42/*------------------------------------------------------------*/
43
44/* for all threads */
45CommandLineOptions CLG_(clo);
46Statistics CLG_(stat);
47Bool CLG_(instrument_state) = True; /* Instrumentation on ? */
48
49/* thread and signal handler specific */
50exec_state CLG_(current_state);
51
52
53/*------------------------------------------------------------*/
54/*--- Statistics ---*/
55/*------------------------------------------------------------*/
56
57static void CLG_(init_statistics)(Statistics* s)
58{
59 s->call_counter = 0;
60 s->jcnd_counter = 0;
61 s->jump_counter = 0;
62 s->rec_call_counter = 0;
63 s->ret_counter = 0;
64 s->bb_executions = 0;
65
66 s->context_counter = 0;
67 s->bb_retranslations = 0;
68
69 s->distinct_objs = 0;
70 s->distinct_files = 0;
71 s->distinct_fns = 0;
72 s->distinct_contexts = 0;
73 s->distinct_bbs = 0;
74 s->distinct_bbccs = 0;
75 s->distinct_instrs = 0;
76 s->distinct_skips = 0;
77
78 s->bb_hash_resizes = 0;
79 s->bbcc_hash_resizes = 0;
80 s->jcc_hash_resizes = 0;
81 s->cxt_hash_resizes = 0;
82 s->fn_array_resizes = 0;
83 s->call_stack_resizes = 0;
84 s->fn_stack_resizes = 0;
85
86 s->full_debug_BBs = 0;
87 s->file_line_debug_BBs = 0;
88 s->fn_name_debug_BBs = 0;
89 s->no_debug_BBs = 0;
90 s->bbcc_lru_misses = 0;
91 s->jcc_lru_misses = 0;
92 s->cxt_lru_misses = 0;
93 s->bbcc_clones = 0;
94}
95
96
weidendoa17f2a32006-03-20 10:27:30 +000097/*------------------------------------------------------------*/
weidendo0a1951d2009-06-15 00:16:36 +000098/*--- Instrumentation structures and event queue handling ---*/
weidendoa17f2a32006-03-20 10:27:30 +000099/*------------------------------------------------------------*/
100
weidendo0a1951d2009-06-15 00:16:36 +0000101/* Maintain an ordered list of memory events which are outstanding, in
102 the sense that no IR has yet been generated to do the relevant
103 helper calls. The BB is scanned top to bottom and memory events
104 are added to the end of the list, merging with the most recent
105 notified event where possible (Dw immediately following Dr and
106 having the same size and EA can be merged).
weidendoa17f2a32006-03-20 10:27:30 +0000107
weidendo0a1951d2009-06-15 00:16:36 +0000108 This merging is done so that for architectures which have
109 load-op-store instructions (x86, amd64), the insn is treated as if
110 it makes just one memory reference (a modify), rather than two (a
111 read followed by a write at the same address).
112
113 At various points the list will need to be flushed, that is, IR
114 generated from it. That must happen before any possible exit from
115 the block (the end, or an IRStmt_Exit). Flushing also takes place
116 when there is no space to add a new event.
117
118 If we require the simulation statistics to be up to date with
119 respect to possible memory exceptions, then the list would have to
120 be flushed before each memory reference. That would however lose
121 performance by inhibiting event-merging during flushing.
122
123 Flushing the list consists of walking it start to end and emitting
124 instrumentation IR for each event, in the order in which they
125 appear. It may be possible to emit a single call for two adjacent
126 events in order to reduce the number of helper function calls made.
127 For example, it could well be profitable to handle two adjacent Ir
128 events with a single helper call. */
129
130typedef
131 IRExpr
132 IRAtom;
133
134typedef
135 enum {
136 Ev_Ir, // Instruction read
137 Ev_Dr, // Data read
138 Ev_Dw, // Data write
139 Ev_Dm, // Data modify (read then write)
140 }
141 EventTag;
142
143typedef
144 struct {
145 EventTag tag;
146 InstrInfo* inode;
147 union {
148 struct {
149 } Ir;
150 struct {
151 IRAtom* ea;
152 Int szB;
153 } Dr;
154 struct {
155 IRAtom* ea;
156 Int szB;
157 } Dw;
158 struct {
159 IRAtom* ea;
160 Int szB;
161 } Dm;
162 } Ev;
163 }
164 Event;
165
166static void init_Event ( Event* ev ) {
167 VG_(memset)(ev, 0, sizeof(Event));
weidendoa17f2a32006-03-20 10:27:30 +0000168}
169
weidendo0a1951d2009-06-15 00:16:36 +0000170static IRAtom* get_Event_dea ( Event* ev ) {
171 switch (ev->tag) {
172 case Ev_Dr: return ev->Ev.Dr.ea;
173 case Ev_Dw: return ev->Ev.Dw.ea;
174 case Ev_Dm: return ev->Ev.Dm.ea;
175 default: tl_assert(0);
176 }
177}
weidendoa17f2a32006-03-20 10:27:30 +0000178
weidendo0a1951d2009-06-15 00:16:36 +0000179static Int get_Event_dszB ( Event* ev ) {
180 switch (ev->tag) {
181 case Ev_Dr: return ev->Ev.Dr.szB;
182 case Ev_Dw: return ev->Ev.Dw.szB;
183 case Ev_Dm: return ev->Ev.Dm.szB;
184 default: tl_assert(0);
185 }
186}
187
188
189/* Up to this many unnotified events are allowed. Number is
190 arbitrary. Larger numbers allow more event merging to occur, but
191 potentially induce more spilling due to extending live ranges of
192 address temporaries. */
193#define N_EVENTS 16
194
195
196/* A struct which holds all the running state during instrumentation.
197 Mostly to avoid passing loads of parameters everywhere. */
198typedef struct {
199 /* The current outstanding-memory-event list. */
200 Event events[N_EVENTS];
201 Int events_used;
202
203 /* The array of InstrInfo's is part of BB struct. */
204 BB* bb;
205
206 /* BB seen before (ie. re-instrumentation) */
207 Bool seen_before;
208
209 /* Number InstrInfo bins 'used' so far. */
210 UInt ii_index;
211
212 // current offset of guest instructions from BB start
213 UInt instr_offset;
214
215 /* The output SB being constructed. */
216 IRSB* sbOut;
217} ClgState;
218
219
220static void showEvent ( Event* ev )
221{
222 switch (ev->tag) {
223 case Ev_Ir:
224 VG_(printf)("Ir (InstrInfo %p) at +%d\n",
225 ev->inode, ev->inode->instr_offset);
226 break;
227 case Ev_Dr:
228 VG_(printf)("Dr (InstrInfo %p) at +%d %d EA=",
229 ev->inode, ev->inode->instr_offset, ev->Ev.Dr.szB);
230 ppIRExpr(ev->Ev.Dr.ea);
231 VG_(printf)("\n");
232 break;
233 case Ev_Dw:
234 VG_(printf)("Dw (InstrInfo %p) at +%d %d EA=",
235 ev->inode, ev->inode->instr_offset, ev->Ev.Dw.szB);
236 ppIRExpr(ev->Ev.Dw.ea);
237 VG_(printf)("\n");
238 break;
239 case Ev_Dm:
240 VG_(printf)("Dm (InstrInfo %p) at +%d %d EA=",
241 ev->inode, ev->inode->instr_offset, ev->Ev.Dm.szB);
242 ppIRExpr(ev->Ev.Dm.ea);
243 VG_(printf)("\n");
244 break;
245 default:
246 tl_assert(0);
247 break;
248 }
249}
250
251/* Generate code for all outstanding memory events, and mark the queue
252 empty. Code is generated into cgs->sbOut, and this activity
253 'consumes' slots in cgs->bb. */
254
255static void flushEvents ( ClgState* clgs )
256{
257 Int i, regparms, inew;
258 Char* helperName;
259 void* helperAddr;
260 IRExpr** argv;
261 IRExpr* i_node_expr;
262 IRDirty* di;
263 Event* ev;
264 Event* ev2;
265 Event* ev3;
266
267 if (!clgs->seen_before) {
268 // extend event sets as needed
269 // available sets: D0 Dr
270 for(i=0; i<clgs->events_used; i++) {
271 ev = &clgs->events[i];
272 switch(ev->tag) {
273 case Ev_Ir:
274 // Ir event always is first for a guest instruction
275 CLG_ASSERT(ev->inode->eventset == 0);
weidendo5bba5252010-06-09 22:32:53 +0000276 ev->inode->eventset = CLG_(sets).base;
weidendo0a1951d2009-06-15 00:16:36 +0000277 break;
278 case Ev_Dr:
279 // extend event set by Dr counter
weidendo5bba5252010-06-09 22:32:53 +0000280 ev->inode->eventset = CLG_(add_event_group)(ev->inode->eventset,
281 EG_DR);
weidendo0a1951d2009-06-15 00:16:36 +0000282 break;
283 case Ev_Dw:
284 case Ev_Dm:
285 // extend event set by Dw counter
weidendo5bba5252010-06-09 22:32:53 +0000286 ev->inode->eventset = CLG_(add_event_group)(ev->inode->eventset,
287 EG_DW);
weidendo0a1951d2009-06-15 00:16:36 +0000288 break;
289 default:
290 tl_assert(0);
291 }
292 }
293 }
294
295 for(i = 0; i < clgs->events_used; i = inew) {
296
297 helperName = NULL;
298 helperAddr = NULL;
299 argv = NULL;
300 regparms = 0;
301
302 /* generate IR to notify event i and possibly the ones
303 immediately following it. */
304 tl_assert(i >= 0 && i < clgs->events_used);
305
306 ev = &clgs->events[i];
307 ev2 = ( i < clgs->events_used-1 ? &clgs->events[i+1] : NULL );
308 ev3 = ( i < clgs->events_used-2 ? &clgs->events[i+2] : NULL );
309
310 CLG_DEBUGIF(5) {
311 VG_(printf)(" flush ");
312 showEvent( ev );
313 }
314
315 i_node_expr = mkIRExpr_HWord( (HWord)ev->inode );
316
317 /* Decide on helper fn to call and args to pass it, and advance
318 i appropriately.
319 Dm events have same effect as Dw events */
320 switch (ev->tag) {
321 case Ev_Ir:
322 /* Merge an Ir with a following Dr. */
323 if (ev2 && ev2->tag == Ev_Dr) {
324 /* Why is this true? It's because we're merging an Ir
325 with a following Dr. The Ir derives from the
326 instruction's IMark and the Dr from data
327 references which follow it. In short it holds
328 because each insn starts with an IMark, hence an
329 Ev_Ir, and so these Dr must pertain to the
330 immediately preceding Ir. Same applies to analogous
331 assertions in the subsequent cases. */
332 tl_assert(ev2->inode == ev->inode);
333 helperName = CLG_(cachesim).log_1I1Dr_name;
334 helperAddr = CLG_(cachesim).log_1I1Dr;
335 argv = mkIRExprVec_3( i_node_expr,
336 get_Event_dea(ev2),
337 mkIRExpr_HWord( get_Event_dszB(ev2) ) );
338 regparms = 3;
339 inew = i+2;
340 }
341 /* Merge an Ir with a following Dw/Dm. */
342 else
343 if (ev2 && (ev2->tag == Ev_Dw || ev2->tag == Ev_Dm)) {
344 tl_assert(ev2->inode == ev->inode);
345 helperName = CLG_(cachesim).log_1I1Dw_name;
346 helperAddr = CLG_(cachesim).log_1I1Dw;
347 argv = mkIRExprVec_3( i_node_expr,
348 get_Event_dea(ev2),
349 mkIRExpr_HWord( get_Event_dszB(ev2) ) );
350 regparms = 3;
351 inew = i+2;
352 }
353 /* Merge an Ir with two following Irs. */
354 else
355 if (ev2 && ev3 && ev2->tag == Ev_Ir && ev3->tag == Ev_Ir) {
356 helperName = CLG_(cachesim).log_3I0D_name;
357 helperAddr = CLG_(cachesim).log_3I0D;
358 argv = mkIRExprVec_3( i_node_expr,
359 mkIRExpr_HWord( (HWord)ev2->inode ),
360 mkIRExpr_HWord( (HWord)ev3->inode ) );
361 regparms = 3;
362 inew = i+3;
363 }
364 /* Merge an Ir with one following Ir. */
365 else
366 if (ev2 && ev2->tag == Ev_Ir) {
367 helperName = CLG_(cachesim).log_2I0D_name;
368 helperAddr = CLG_(cachesim).log_2I0D;
369 argv = mkIRExprVec_2( i_node_expr,
370 mkIRExpr_HWord( (HWord)ev2->inode ) );
371 regparms = 2;
372 inew = i+2;
373 }
374 /* No merging possible; emit as-is. */
375 else {
376 helperName = CLG_(cachesim).log_1I0D_name;
377 helperAddr = CLG_(cachesim).log_1I0D;
378 argv = mkIRExprVec_1( i_node_expr );
379 regparms = 1;
380 inew = i+1;
381 }
382 break;
383 case Ev_Dr:
384 /* Data read or modify */
weidendoa17f2a32006-03-20 10:27:30 +0000385 helperName = CLG_(cachesim).log_0I1Dr_name;
386 helperAddr = CLG_(cachesim).log_0I1Dr;
weidendo0a1951d2009-06-15 00:16:36 +0000387 argv = mkIRExprVec_3( i_node_expr,
388 get_Event_dea(ev),
389 mkIRExpr_HWord( get_Event_dszB(ev) ) );
390 regparms = 3;
391 inew = i+1;
392 break;
393 case Ev_Dw:
394 case Ev_Dm:
395 /* Data write */
weidendoa17f2a32006-03-20 10:27:30 +0000396 helperName = CLG_(cachesim).log_0I1Dw_name;
397 helperAddr = CLG_(cachesim).log_0I1Dw;
weidendo0a1951d2009-06-15 00:16:36 +0000398 argv = mkIRExprVec_3( i_node_expr,
399 get_Event_dea(ev),
400 mkIRExpr_HWord( get_Event_dszB(ev) ) );
401 regparms = 3;
402 inew = i+1;
403 break;
404 default:
405 tl_assert(0);
406 }
weidendoa17f2a32006-03-20 10:27:30 +0000407
weidendo0a1951d2009-06-15 00:16:36 +0000408 CLG_DEBUGIF(5) {
409 if (inew > i+1) {
410 VG_(printf)(" merge ");
411 showEvent( ev2 );
412 }
413 if (inew > i+2) {
414 VG_(printf)(" merge ");
415 showEvent( ev3 );
416 }
417 if (helperAddr)
418 VG_(printf)(" call %s (%p)\n",
419 helperName, helperAddr);
420 }
weidendoa17f2a32006-03-20 10:27:30 +0000421
weidendo0a1951d2009-06-15 00:16:36 +0000422 /* helper could be unset depending on the simulator used */
423 if (helperAddr == 0) continue;
weidendoa17f2a32006-03-20 10:27:30 +0000424
weidendo0a1951d2009-06-15 00:16:36 +0000425 /* Add the helper. */
426 tl_assert(helperName);
427 tl_assert(helperAddr);
428 tl_assert(argv);
429 di = unsafeIRDirty_0_N( regparms,
430 helperName, VG_(fnptr_to_fnentry)( helperAddr ),
431 argv );
432 addStmtToIRSB( clgs->sbOut, IRStmt_Dirty(di) );
weidendoa17f2a32006-03-20 10:27:30 +0000433 }
434
weidendo0a1951d2009-06-15 00:16:36 +0000435 clgs->events_used = 0;
436}
weidendoa17f2a32006-03-20 10:27:30 +0000437
weidendo0a1951d2009-06-15 00:16:36 +0000438static void addEvent_Ir ( ClgState* clgs, InstrInfo* inode )
439{
440 Event* evt;
441 tl_assert(clgs->seen_before || (inode->eventset == 0));
442 if (!CLG_(clo).simulate_cache) return;
weidendoa17f2a32006-03-20 10:27:30 +0000443
weidendo0a1951d2009-06-15 00:16:36 +0000444 if (clgs->events_used == N_EVENTS)
445 flushEvents(clgs);
446 tl_assert(clgs->events_used >= 0 && clgs->events_used < N_EVENTS);
447 evt = &clgs->events[clgs->events_used];
448 init_Event(evt);
449 evt->tag = Ev_Ir;
450 evt->inode = inode;
451 clgs->events_used++;
452}
weidendoa17f2a32006-03-20 10:27:30 +0000453
weidendo0a1951d2009-06-15 00:16:36 +0000454static
455void addEvent_Dr ( ClgState* clgs, InstrInfo* inode, Int datasize, IRAtom* ea )
456{
457 Event* evt;
458 tl_assert(isIRAtom(ea));
459 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
460 if (!CLG_(clo).simulate_cache) return;
weidendoc8e76152006-05-27 15:30:58 +0000461
weidendo0a1951d2009-06-15 00:16:36 +0000462 if (clgs->events_used == N_EVENTS)
463 flushEvents(clgs);
464 tl_assert(clgs->events_used >= 0 && clgs->events_used < N_EVENTS);
465 evt = &clgs->events[clgs->events_used];
466 init_Event(evt);
467 evt->tag = Ev_Dr;
468 evt->inode = inode;
469 evt->Ev.Dr.szB = datasize;
470 evt->Ev.Dr.ea = ea;
471 clgs->events_used++;
472}
weidendoc8e76152006-05-27 15:30:58 +0000473
weidendo0a1951d2009-06-15 00:16:36 +0000474static
475void addEvent_Dw ( ClgState* clgs, InstrInfo* inode, Int datasize, IRAtom* ea )
476{
477 Event* lastEvt;
478 Event* evt;
479 tl_assert(isIRAtom(ea));
480 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
481 if (!CLG_(clo).simulate_cache) return;
weidendoc8e76152006-05-27 15:30:58 +0000482
weidendo0a1951d2009-06-15 00:16:36 +0000483 /* Is it possible to merge this write with the preceding read? */
484 lastEvt = &clgs->events[clgs->events_used-1];
485 if (clgs->events_used > 0
486 && lastEvt->tag == Ev_Dr
487 && lastEvt->Ev.Dr.szB == datasize
488 && lastEvt->inode == inode
489 && eqIRAtom(lastEvt->Ev.Dr.ea, ea))
490 {
491 lastEvt->tag = Ev_Dm;
492 return;
493 }
weidendoc8e76152006-05-27 15:30:58 +0000494
weidendo0a1951d2009-06-15 00:16:36 +0000495 /* No. Add as normal. */
496 if (clgs->events_used == N_EVENTS)
497 flushEvents(clgs);
498 tl_assert(clgs->events_used >= 0 && clgs->events_used < N_EVENTS);
499 evt = &clgs->events[clgs->events_used];
500 init_Event(evt);
501 evt->tag = Ev_Dw;
502 evt->inode = inode;
503 evt->Ev.Dw.szB = datasize;
504 evt->Ev.Dw.ea = ea;
505 clgs->events_used++;
506}
507
508/* Initialise or check (if already seen before) an InstrInfo for next insn.
509 We only can set instr_offset/instr_size here. The required event set and
510 resulting cost offset depend on events (Ir/Dr/Dw/Dm) in guest
511 instructions. The event set is extended as required on flush of the event
512 queue (when Dm events were determined), cost offsets are determined at
513 end of BB instrumentation. */
514static
515InstrInfo* next_InstrInfo ( ClgState* clgs, UInt instr_size )
516{
517 InstrInfo* ii;
518 tl_assert(clgs->ii_index >= 0);
519 tl_assert(clgs->ii_index < clgs->bb->instr_count);
520 ii = &clgs->bb->instr[ clgs->ii_index ];
521
522 if (clgs->seen_before) {
523 CLG_ASSERT(ii->instr_offset == clgs->instr_offset);
524 CLG_ASSERT(ii->instr_size == instr_size);
weidendoa17f2a32006-03-20 10:27:30 +0000525 }
526 else {
weidendo0a1951d2009-06-15 00:16:36 +0000527 ii->instr_offset = clgs->instr_offset;
528 ii->instr_size = instr_size;
529 ii->cost_offset = 0;
530 ii->eventset = 0;
weidendoa17f2a32006-03-20 10:27:30 +0000531 }
532
weidendo0a1951d2009-06-15 00:16:36 +0000533 clgs->ii_index++;
534 clgs->instr_offset += instr_size;
535 CLG_(stat).distinct_instrs++;
weidendoa17f2a32006-03-20 10:27:30 +0000536
weidendo0a1951d2009-06-15 00:16:36 +0000537 return ii;
weidendoa17f2a32006-03-20 10:27:30 +0000538}
539
weidendo0a1951d2009-06-15 00:16:36 +0000540// return total number of cost values needed for this BB
541static
542UInt update_cost_offsets( ClgState* clgs )
543{
544 Int i;
545 InstrInfo* ii;
546 UInt cost_offset = 0;
547
548 CLG_ASSERT(clgs->bb->instr_count == clgs->ii_index);
549 for(i=0; i<clgs->ii_index; i++) {
550 ii = &clgs->bb->instr[i];
551 if (clgs->seen_before) {
552 CLG_ASSERT(ii->cost_offset == cost_offset);
553 } else
554 ii->cost_offset = cost_offset;
555 cost_offset += ii->eventset ? ii->eventset->size : 0;
556 }
557
558 return cost_offset;
559}
560
561/*------------------------------------------------------------*/
562/*--- Instrumentation ---*/
563/*------------------------------------------------------------*/
564
weidendoa17f2a32006-03-20 10:27:30 +0000565#if defined(VG_BIGENDIAN)
566# define CLGEndness Iend_BE
567#elif defined(VG_LITTLEENDIAN)
568# define CLGEndness Iend_LE
569#else
570# error "Unknown endianness"
571#endif
572
573static
574Addr IRConst2Addr(IRConst* con)
575{
576 Addr addr;
577
578 if (sizeof(Addr) == 4) {
579 CLG_ASSERT( con->tag == Ico_U32 );
580 addr = con->Ico.U32;
581 }
582 else if (sizeof(Addr) == 8) {
583 CLG_ASSERT( con->tag == Ico_U64 );
584 addr = con->Ico.U64;
585 }
586 else
587 VG_(tool_panic)("Callgrind: invalid Addr type");
588
589 return addr;
590}
591
592/* First pass over a BB to instrument, counting instructions and jumps
593 * This is needed for the size of the BB struct to allocate
594 *
595 * Called from CLG_(get_bb)
596 */
weidendo0a1951d2009-06-15 00:16:36 +0000597void CLG_(collectBlockInfo)(IRSB* sbIn,
weidendoa17f2a32006-03-20 10:27:30 +0000598 /*INOUT*/ UInt* instrs,
599 /*INOUT*/ UInt* cjmps,
600 /*INOUT*/ Bool* cjmp_inverted)
601{
602 Int i;
603 IRStmt* st;
604 Addr instrAddr =0, jumpDst;
605 UInt instrLen = 0;
606 Bool toNextInstr = False;
607
608 // Ist_Exit has to be ignored in preamble code, before first IMark:
609 // preamble code is added by VEX for self modifying code, and has
610 // nothing to do with client code
611 Bool inPreamble = True;
612
weidendo0a1951d2009-06-15 00:16:36 +0000613 if (!sbIn) return;
weidendoa17f2a32006-03-20 10:27:30 +0000614
weidendo0a1951d2009-06-15 00:16:36 +0000615 for (i = 0; i < sbIn->stmts_used; i++) {
616 st = sbIn->stmts[i];
weidendoa17f2a32006-03-20 10:27:30 +0000617 if (Ist_IMark == st->tag) {
618 inPreamble = False;
619
620 instrAddr = (Addr)ULong_to_Ptr(st->Ist.IMark.addr);
621 instrLen = st->Ist.IMark.len;
622
623 (*instrs)++;
624 toNextInstr = False;
625 }
626 if (inPreamble) continue;
627 if (Ist_Exit == st->tag) {
628 jumpDst = IRConst2Addr(st->Ist.Exit.dst);
629 toNextInstr = (jumpDst == instrAddr + instrLen);
weidendo0a1951d2009-06-15 00:16:36 +0000630
weidendoa17f2a32006-03-20 10:27:30 +0000631 (*cjmps)++;
632 }
633 }
634
635 /* if the last instructions of BB conditionally jumps to next instruction
636 * (= first instruction of next BB in memory), this is a inverted by VEX.
637 */
638 *cjmp_inverted = toNextInstr;
639}
640
641static
sewardj0b9d74a2006-12-24 02:24:11 +0000642void addConstMemStoreStmt( IRSB* bbOut, UWord addr, UInt val, IRType hWordTy)
weidendoa17f2a32006-03-20 10:27:30 +0000643{
sewardj0b9d74a2006-12-24 02:24:11 +0000644 addStmtToIRSB( bbOut,
weidendoa17f2a32006-03-20 10:27:30 +0000645 IRStmt_Store(CLGEndness,
646 IRExpr_Const(hWordTy == Ity_I32 ?
647 IRConst_U32( addr ) :
648 IRConst_U64( addr )),
649 IRExpr_Const(IRConst_U32(val)) ));
650}
651
weidendo0a1951d2009-06-15 00:16:36 +0000652
653/* add helper call to setup_bbcc, with pointer to BB struct as argument
654 *
655 * precondition for setup_bbcc:
656 * - jmps_passed has number of cond.jumps passed in last executed BB
657 * - current_bbcc has a pointer to the BBCC of the last executed BB
658 * Thus, if bbcc_jmpkind is != -1 (JmpNone),
659 * current_bbcc->bb->jmp_addr
660 * gives the address of the jump source.
661 *
662 * the setup does 2 things:
663 * - trace call:
664 * * Unwind own call stack, i.e sync our ESP with real ESP
665 * This is for ESP manipulation (longjmps, C++ exec handling) and RET
666 * * For CALLs or JMPs crossing objects, record call arg +
667 * push are on own call stack
668 *
669 * - prepare for cache log functions:
670 * set current_bbcc to BBCC that gets the costs for this BB execution
671 * attached
672 */
673static
674void addBBSetupCall(ClgState* clgs)
675{
676 IRDirty* di;
677 IRExpr *arg1, **argv;
678
679 arg1 = mkIRExpr_HWord( (HWord)clgs->bb );
680 argv = mkIRExprVec_1(arg1);
681 di = unsafeIRDirty_0_N( 1, "setup_bbcc",
682 VG_(fnptr_to_fnentry)( & CLG_(setup_bbcc) ),
683 argv);
684 addStmtToIRSB( clgs->sbOut, IRStmt_Dirty(di) );
685}
686
687
weidendoa17f2a32006-03-20 10:27:30 +0000688static
sewardj0b9d74a2006-12-24 02:24:11 +0000689IRSB* CLG_(instrument)( VgCallbackClosure* closure,
weidendo0a1951d2009-06-15 00:16:36 +0000690 IRSB* sbIn,
weidendoa17f2a32006-03-20 10:27:30 +0000691 VexGuestLayout* layout,
692 VexGuestExtents* vge,
693 IRType gWordTy, IRType hWordTy )
694{
weidendo0a1951d2009-06-15 00:16:36 +0000695 Int i, isize;
696 IRStmt* st;
697 Addr origAddr;
698 InstrInfo* curr_inode = NULL;
699 ClgState clgs;
700 UInt cJumps = 0;
weidendoa17f2a32006-03-20 10:27:30 +0000701
weidendoa17f2a32006-03-20 10:27:30 +0000702
703 if (gWordTy != hWordTy) {
704 /* We don't currently support this case. */
705 VG_(tool_panic)("host/guest word size mismatch");
706 }
707
708 // No instrumentation if it is switched off
709 if (! CLG_(instrument_state)) {
barta0b6b2c2008-07-07 06:49:24 +0000710 CLG_DEBUG(5, "instrument(BB %#lx) [Instrumentation OFF]\n",
weidendoa17f2a32006-03-20 10:27:30 +0000711 (Addr)closure->readdr);
weidendo0a1951d2009-06-15 00:16:36 +0000712 return sbIn;
weidendoa17f2a32006-03-20 10:27:30 +0000713 }
714
barta0b6b2c2008-07-07 06:49:24 +0000715 CLG_DEBUG(3, "+ instrument(BB %#lx)\n", (Addr)closure->readdr);
weidendoa17f2a32006-03-20 10:27:30 +0000716
sewardj0b9d74a2006-12-24 02:24:11 +0000717 /* Set up SB for instrumented IR */
weidendo0a1951d2009-06-15 00:16:36 +0000718 clgs.sbOut = deepCopyIRSBExceptStmts(sbIn);
weidendoa17f2a32006-03-20 10:27:30 +0000719
720 // Copy verbatim any IR preamble preceding the first IMark
721 i = 0;
weidendo0a1951d2009-06-15 00:16:36 +0000722 while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
723 addStmtToIRSB( clgs.sbOut, sbIn->stmts[i] );
weidendoa17f2a32006-03-20 10:27:30 +0000724 i++;
725 }
726
727 // Get the first statement, and origAddr from it
weidendo0a1951d2009-06-15 00:16:36 +0000728 CLG_ASSERT(sbIn->stmts_used >0);
729 CLG_ASSERT(i < sbIn->stmts_used);
730 st = sbIn->stmts[i];
weidendoa17f2a32006-03-20 10:27:30 +0000731 CLG_ASSERT(Ist_IMark == st->tag);
weidendo0a1951d2009-06-15 00:16:36 +0000732
733 origAddr = (Addr)st->Ist.IMark.addr;
weidendoa17f2a32006-03-20 10:27:30 +0000734 CLG_ASSERT(origAddr == st->Ist.IMark.addr); // XXX: check no overflow
735
weidendo0a1951d2009-06-15 00:16:36 +0000736 /* Get BB struct (creating if necessary).
weidendoa17f2a32006-03-20 10:27:30 +0000737 * JS: The hash table is keyed with orig_addr_noredir -- important!
738 * JW: Why? If it is because of different chasing of the redirection,
739 * this is not needed, as chasing is switched off in callgrind
740 */
weidendo0a1951d2009-06-15 00:16:36 +0000741 clgs.bb = CLG_(get_bb)(origAddr, sbIn, &(clgs.seen_before));
weidendoa17f2a32006-03-20 10:27:30 +0000742
weidendo0a1951d2009-06-15 00:16:36 +0000743 addBBSetupCall(&clgs);
weidendoa17f2a32006-03-20 10:27:30 +0000744
weidendo0a1951d2009-06-15 00:16:36 +0000745 // Set up running state
746 clgs.events_used = 0;
747 clgs.ii_index = 0;
748 clgs.instr_offset = 0;
weidendoa17f2a32006-03-20 10:27:30 +0000749
weidendo0a1951d2009-06-15 00:16:36 +0000750 for (/*use current i*/; i < sbIn->stmts_used; i++) {
weidendoa17f2a32006-03-20 10:27:30 +0000751
weidendo0a1951d2009-06-15 00:16:36 +0000752 st = sbIn->stmts[i];
753 CLG_ASSERT(isFlatIRStmt(st));
weidendoa17f2a32006-03-20 10:27:30 +0000754
weidendo0a1951d2009-06-15 00:16:36 +0000755 switch (st->tag) {
756 case Ist_NoOp:
757 case Ist_AbiHint:
758 case Ist_Put:
759 case Ist_PutI:
760 case Ist_MBE:
761 break;
weidendoa17f2a32006-03-20 10:27:30 +0000762
weidendo0a1951d2009-06-15 00:16:36 +0000763 case Ist_IMark: {
764 CLG_ASSERT(clgs.instr_offset == (Addr)st->Ist.IMark.addr - origAddr);
765 isize = st->Ist.IMark.len;
766 // If Vex fails to decode an instruction, the size will be zero.
767 // Pretend otherwise.
768 if (isize == 0) isize = VG_MIN_INSTR_SZB;
weidendoa17f2a32006-03-20 10:27:30 +0000769
weidendo0a1951d2009-06-15 00:16:36 +0000770 // Sanity-check size.
771 tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
772 || VG_CLREQ_SZB == isize );
weidendoa17f2a32006-03-20 10:27:30 +0000773
weidendo0a1951d2009-06-15 00:16:36 +0000774 // Init the inode, record it as the current one.
775 // Subsequent Dr/Dw/Dm events from the same instruction will
776 // also use it.
777 curr_inode = next_InstrInfo (&clgs, isize);
weidendoa17f2a32006-03-20 10:27:30 +0000778
weidendo0a1951d2009-06-15 00:16:36 +0000779 addEvent_Ir( &clgs, curr_inode );
780 break;
781 }
weidendoa17f2a32006-03-20 10:27:30 +0000782
weidendo0a1951d2009-06-15 00:16:36 +0000783 case Ist_WrTmp: {
784 IRExpr* data = st->Ist.WrTmp.data;
785 if (data->tag == Iex_Load) {
786 IRExpr* aexpr = data->Iex.Load.addr;
787 // Note also, endianness info is ignored. I guess
788 // that's not interesting.
789 addEvent_Dr( &clgs, curr_inode,
790 sizeofIRType(data->Iex.Load.ty), aexpr );
791 }
792 break;
793 }
weidendoa17f2a32006-03-20 10:27:30 +0000794
weidendo0a1951d2009-06-15 00:16:36 +0000795 case Ist_Store: {
796 IRExpr* data = st->Ist.Store.data;
797 IRExpr* aexpr = st->Ist.Store.addr;
798 addEvent_Dw( &clgs, curr_inode,
799 sizeofIRType(typeOfIRExpr(sbIn->tyenv, data)), aexpr );
800 break;
801 }
weidendoa17f2a32006-03-20 10:27:30 +0000802
weidendo0a1951d2009-06-15 00:16:36 +0000803 case Ist_Dirty: {
804 Int dataSize;
805 IRDirty* d = st->Ist.Dirty.details;
806 if (d->mFx != Ifx_None) {
807 /* This dirty helper accesses memory. Collect the details. */
808 tl_assert(d->mAddr != NULL);
809 tl_assert(d->mSize != 0);
810 dataSize = d->mSize;
811 // Large (eg. 28B, 108B, 512B on x86) data-sized
812 // instructions will be done inaccurately, but they're
813 // very rare and this avoids errors from hitting more
814 // than two cache lines in the simulation.
815 if (dataSize > MIN_LINE_SIZE)
816 dataSize = MIN_LINE_SIZE;
817 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
818 addEvent_Dr( &clgs, curr_inode, dataSize, d->mAddr );
819 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
820 addEvent_Dw( &clgs, curr_inode, dataSize, d->mAddr );
821 } else {
822 tl_assert(d->mAddr == NULL);
823 tl_assert(d->mSize == 0);
824 }
825 break;
826 }
weidendoa17f2a32006-03-20 10:27:30 +0000827
sewardj1c0ce7a2009-07-01 08:10:49 +0000828 case Ist_CAS: {
829 /* We treat it as a read and a write of the location. I
830 think that is the same behaviour as it was before IRCAS
831 was introduced, since prior to that point, the Vex
832 front ends would translate a lock-prefixed instruction
833 into a (normal) read followed by a (normal) write. */
834 Int dataSize;
835 IRCAS* cas = st->Ist.CAS.details;
836 CLG_ASSERT(cas->addr && isIRAtom(cas->addr));
837 CLG_ASSERT(cas->dataLo);
838 dataSize = sizeofIRType(typeOfIRExpr(sbIn->tyenv, cas->dataLo));
839 if (cas->dataHi != NULL)
840 dataSize *= 2; /* since this is a doubleword-cas */
841 addEvent_Dr( &clgs, curr_inode, dataSize, cas->addr );
842 addEvent_Dw( &clgs, curr_inode, dataSize, cas->addr );
843 break;
844 }
sewardjdb5907d2009-11-26 17:20:21 +0000845
846 case Ist_LLSC: {
847 IRType dataTy;
848 if (st->Ist.LLSC.storedata == NULL) {
849 /* LL */
850 dataTy = typeOfIRTemp(sbIn->tyenv, st->Ist.LLSC.result);
851 addEvent_Dr( &clgs, curr_inode,
852 sizeofIRType(dataTy), st->Ist.LLSC.addr );
853 } else {
854 /* SC */
855 dataTy = typeOfIRExpr(sbIn->tyenv, st->Ist.LLSC.storedata);
856 addEvent_Dw( &clgs, curr_inode,
857 sizeofIRType(dataTy), st->Ist.LLSC.addr );
858 }
859 break;
860 }
861
862 case Ist_Exit: {
weidendo0a1951d2009-06-15 00:16:36 +0000863 UInt jmps_passed;
weidendoa17f2a32006-03-20 10:27:30 +0000864
weidendo0a1951d2009-06-15 00:16:36 +0000865 /* We may never reach the next statement, so need to flush
866 all outstanding transactions now. */
867 flushEvents( &clgs );
weidendoa17f2a32006-03-20 10:27:30 +0000868
weidendo0a1951d2009-06-15 00:16:36 +0000869 CLG_ASSERT(clgs.ii_index>0);
870 if (!clgs.seen_before) {
871 clgs.bb->jmp[cJumps].instr = clgs.ii_index-1;
872 clgs.bb->jmp[cJumps].skip = False;
873 }
874
875 /* Update global variable jmps_passed before the jump
876 * A correction is needed if VEX inverted the last jump condition
877 */
878 jmps_passed = cJumps;
879 if ((cJumps+1 == clgs.bb->cjmp_count) && clgs.bb->cjmp_inverted)
880 jmps_passed++;
881 addConstMemStoreStmt( clgs.sbOut,
882 (UWord) &CLG_(current_state).jmps_passed,
883 jmps_passed, hWordTy);
884 cJumps++;
885
886 break;
887 }
888
889 default:
890 tl_assert(0);
891 break;
892 }
893
894 /* Copy the original statement */
895 addStmtToIRSB( clgs.sbOut, st );
896
897 CLG_DEBUGIF(5) {
898 VG_(printf)(" pass ");
899 ppIRStmt(st);
900 VG_(printf)("\n");
901 }
weidendoa17f2a32006-03-20 10:27:30 +0000902 }
weidendoa17f2a32006-03-20 10:27:30 +0000903
weidendo0a1951d2009-06-15 00:16:36 +0000904 /* At the end of the bb. Flush outstandings. */
905 flushEvents( &clgs );
906
907 /* Always update global variable jmps_passed at end of bb.
weidendoa17f2a32006-03-20 10:27:30 +0000908 * A correction is needed if VEX inverted the last jump condition
909 */
weidendo0a1951d2009-06-15 00:16:36 +0000910 {
911 UInt jmps_passed = cJumps;
912 if (clgs.bb->cjmp_inverted) jmps_passed--;
913 addConstMemStoreStmt( clgs.sbOut,
914 (UWord) &CLG_(current_state).jmps_passed,
915 jmps_passed, hWordTy);
916 }
917 CLG_ASSERT(clgs.bb->cjmp_count == cJumps);
918 CLG_ASSERT(clgs.bb->instr_count = clgs.ii_index);
weidendoa17f2a32006-03-20 10:27:30 +0000919
920 /* This stores the instr of the call/ret at BB end */
weidendo0a1951d2009-06-15 00:16:36 +0000921 clgs.bb->jmp[cJumps].instr = clgs.ii_index-1;
weidendoa17f2a32006-03-20 10:27:30 +0000922
weidendo0a1951d2009-06-15 00:16:36 +0000923 if (clgs.seen_before) {
924 CLG_ASSERT(clgs.bb->cost_count == update_cost_offsets(&clgs));
925 CLG_ASSERT(clgs.bb->instr_len = clgs.instr_offset);
926 CLG_ASSERT(clgs.bb->jmpkind == sbIn->jumpkind);
weidendoa17f2a32006-03-20 10:27:30 +0000927 }
928 else {
weidendo0a1951d2009-06-15 00:16:36 +0000929 clgs.bb->cost_count = update_cost_offsets(&clgs);
930 clgs.bb->instr_len = clgs.instr_offset;
931 clgs.bb->jmpkind = sbIn->jumpkind;
weidendoa17f2a32006-03-20 10:27:30 +0000932 }
weidendo0a1951d2009-06-15 00:16:36 +0000933
barta0b6b2c2008-07-07 06:49:24 +0000934 CLG_DEBUG(3, "- instrument(BB %#lx): byteLen %u, CJumps %u, CostLen %u\n",
weidendo0a1951d2009-06-15 00:16:36 +0000935 origAddr, clgs.bb->instr_len,
936 clgs.bb->cjmp_count, clgs.bb->cost_count);
weidendoa17f2a32006-03-20 10:27:30 +0000937 if (cJumps>0) {
938 CLG_DEBUG(3, " [ ");
939 for (i=0;i<cJumps;i++)
weidendo0a1951d2009-06-15 00:16:36 +0000940 CLG_DEBUG(3, "%d ", clgs.bb->jmp[i].instr);
941 CLG_DEBUG(3, "], last inverted: %s \n",
942 clgs.bb->cjmp_inverted ? "yes":"no");
weidendoa17f2a32006-03-20 10:27:30 +0000943 }
944
weidendo0a1951d2009-06-15 00:16:36 +0000945 return clgs.sbOut;
weidendoa17f2a32006-03-20 10:27:30 +0000946}
947
948/*--------------------------------------------------------------------*/
949/*--- Discarding BB info ---*/
950/*--------------------------------------------------------------------*/
951
952// Called when a translation is removed from the translation cache for
953// any reason at all: to free up space, because the guest code was
954// unmapped or modified, or for any arbitrary reason.
955static
sewardj0b9d74a2006-12-24 02:24:11 +0000956void clg_discard_superblock_info ( Addr64 orig_addr64, VexGuestExtents vge )
weidendoa17f2a32006-03-20 10:27:30 +0000957{
958 Addr orig_addr = (Addr)orig_addr64;
959
960 tl_assert(vge.n_used > 0);
961
962 if (0)
sewardj0b9d74a2006-12-24 02:24:11 +0000963 VG_(printf)( "discard_superblock_info: %p, %p, %llu\n",
weidendoa17f2a32006-03-20 10:27:30 +0000964 (void*)(Addr)orig_addr,
965 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
966
967 // Get BB info, remove from table, free BB info. Simple! Note that we
968 // use orig_addr, not the first instruction address in vge.
969 CLG_(delete_bb)(orig_addr);
970}
971
972
973/*------------------------------------------------------------*/
974/*--- CLG_(fini)() and related function ---*/
975/*------------------------------------------------------------*/
976
977
978
979static void zero_thread_cost(thread_info* t)
980{
981 Int i;
982
983 for(i = 0; i < CLG_(current_call_stack).sp; i++) {
984 if (!CLG_(current_call_stack).entry[i].jcc) continue;
985
986 /* reset call counters to current for active calls */
987 CLG_(copy_cost)( CLG_(sets).full,
988 CLG_(current_call_stack).entry[i].enter_cost,
989 CLG_(current_state).cost );
weidendoceb06de2009-08-11 20:53:57 +0000990 CLG_(current_call_stack).entry[i].jcc->call_counter = 0;
weidendoa17f2a32006-03-20 10:27:30 +0000991 }
992
993 CLG_(forall_bbccs)(CLG_(zero_bbcc));
994
995 /* set counter for last dump */
996 CLG_(copy_cost)( CLG_(sets).full,
997 t->lastdump_cost, CLG_(current_state).cost );
998}
999
1000void CLG_(zero_all_cost)(Bool only_current_thread)
1001{
1002 if (VG_(clo_verbosity) > 1)
sewardj0f33adf2009-07-15 14:51:03 +00001003 VG_(message)(Vg_DebugMsg, " Zeroing costs...\n");
weidendoa17f2a32006-03-20 10:27:30 +00001004
1005 if (only_current_thread)
1006 zero_thread_cost(CLG_(get_current_thread)());
1007 else
1008 CLG_(forall_threads)(zero_thread_cost);
1009
1010 if (VG_(clo_verbosity) > 1)
sewardj0f33adf2009-07-15 14:51:03 +00001011 VG_(message)(Vg_DebugMsg, " ...done\n");
weidendoa17f2a32006-03-20 10:27:30 +00001012}
1013
1014static
1015void unwind_thread(thread_info* t)
1016{
1017 /* unwind signal handlers */
1018 while(CLG_(current_state).sig !=0)
1019 CLG_(post_signal)(CLG_(current_tid),CLG_(current_state).sig);
1020
1021 /* unwind regular call stack */
1022 while(CLG_(current_call_stack).sp>0)
1023 CLG_(pop_call_stack)();
weidendof3e0b492006-09-10 22:34:20 +00001024
1025 /* reset context and function stack for context generation */
1026 CLG_(init_exec_state)( &CLG_(current_state) );
1027 CLG_(current_fn_stack).top = CLG_(current_fn_stack).bottom;
weidendoa17f2a32006-03-20 10:27:30 +00001028}
1029
weidendoe8914872009-08-11 20:53:59 +00001030static
1031void zero_state_cost(thread_info* t)
1032{
1033 CLG_(zero_cost)( CLG_(sets).full, CLG_(current_state).cost );
1034}
1035
weidendoa17f2a32006-03-20 10:27:30 +00001036/* Ups, this can go wrong... */
1037extern void VG_(discard_translations) ( Addr64 start, ULong range );
1038
1039void CLG_(set_instrument_state)(Char* reason, Bool state)
1040{
1041 if (CLG_(instrument_state) == state) {
1042 CLG_DEBUG(2, "%s: instrumentation already %s\n",
1043 reason, state ? "ON" : "OFF");
1044 return;
1045 }
1046 CLG_(instrument_state) = state;
1047 CLG_DEBUG(2, "%s: Switching instrumentation %s ...\n",
1048 reason, state ? "ON" : "OFF");
1049
1050 VG_(discard_translations)( (Addr64)0x1000, (ULong) ~0xfffl);
1051
1052 /* reset internal state: call stacks, simulator */
1053 CLG_(forall_threads)(unwind_thread);
weidendoe8914872009-08-11 20:53:59 +00001054 CLG_(forall_threads)(zero_state_cost);
weidendoa17f2a32006-03-20 10:27:30 +00001055 (*CLG_(cachesim).clear)();
weidendoa17f2a32006-03-20 10:27:30 +00001056
weidendoa17f2a32006-03-20 10:27:30 +00001057 if (VG_(clo_verbosity) > 1)
sewardj0f33adf2009-07-15 14:51:03 +00001058 VG_(message)(Vg_DebugMsg, "%s: instrumentation switched %s\n",
weidendoa17f2a32006-03-20 10:27:30 +00001059 reason, state ? "ON" : "OFF");
1060}
1061
1062
1063static
1064Bool CLG_(handle_client_request)(ThreadId tid, UWord *args, UWord *ret)
1065{
1066 if (!VG_IS_TOOL_USERREQ('C','T',args[0]))
1067 return False;
1068
1069 switch(args[0]) {
1070 case VG_USERREQ__DUMP_STATS:
1071 CLG_(dump_profile)("Client Request", True);
1072 *ret = 0; /* meaningless */
1073 break;
1074
1075 case VG_USERREQ__DUMP_STATS_AT:
1076 {
1077 Char buf[512];
njn8a7b41b2007-09-23 00:51:24 +00001078 VG_(sprintf)(buf,"Client Request: %s", (Char*)args[1]);
weidendoa17f2a32006-03-20 10:27:30 +00001079 CLG_(dump_profile)(buf, True);
1080 *ret = 0; /* meaningless */
1081 }
1082 break;
1083
1084 case VG_USERREQ__ZERO_STATS:
1085 CLG_(zero_all_cost)(True);
1086 *ret = 0; /* meaningless */
1087 break;
1088
1089 case VG_USERREQ__TOGGLE_COLLECT:
1090 CLG_(current_state).collect = !CLG_(current_state).collect;
1091 CLG_DEBUG(2, "Client Request: toggled collection state to %s\n",
1092 CLG_(current_state).collect ? "ON" : "OFF");
1093 *ret = 0; /* meaningless */
1094 break;
1095
1096 case VG_USERREQ__START_INSTRUMENTATION:
1097 CLG_(set_instrument_state)("Client Request", True);
1098 *ret = 0; /* meaningless */
1099 break;
1100
1101 case VG_USERREQ__STOP_INSTRUMENTATION:
1102 CLG_(set_instrument_state)("Client Request", False);
1103 *ret = 0; /* meaningless */
1104 break;
1105
1106 default:
1107 return False;
1108 }
1109
1110 return True;
1111}
1112
1113
1114/* Syscall Timing */
1115
1116/* struct timeval syscalltime[VG_N_THREADS]; */
1117#if CLG_MICROSYSTIME
1118#include <sys/time.h>
1119#include <sys/syscall.h>
1120extern Int VG_(do_syscall) ( UInt, ... );
1121
1122ULong syscalltime[VG_N_THREADS];
1123#else
1124UInt syscalltime[VG_N_THREADS];
1125#endif
1126
1127static
sewardj1c0ce7a2009-07-01 08:10:49 +00001128void CLG_(pre_syscalltime)(ThreadId tid, UInt syscallno,
1129 UWord* args, UInt nArgs)
weidendoa17f2a32006-03-20 10:27:30 +00001130{
1131 if (CLG_(clo).collect_systime) {
1132#if CLG_MICROSYSTIME
1133 struct vki_timeval tv_now;
1134 VG_(do_syscall)(__NR_gettimeofday, (UInt)&tv_now, (UInt)NULL);
1135 syscalltime[tid] = tv_now.tv_sec * 1000000ULL + tv_now.tv_usec;
1136#else
1137 syscalltime[tid] = VG_(read_millisecond_timer)();
1138#endif
1139 }
1140}
1141
1142static
sewardj1c0ce7a2009-07-01 08:10:49 +00001143void CLG_(post_syscalltime)(ThreadId tid, UInt syscallno,
1144 UWord* args, UInt nArgs, SysRes res)
weidendoa17f2a32006-03-20 10:27:30 +00001145{
weidendoae0bb6f2007-02-16 13:12:43 +00001146 if (CLG_(clo).collect_systime &&
1147 CLG_(current_state).bbcc) {
weidendo5bba5252010-06-09 22:32:53 +00001148 Int o;
weidendoa17f2a32006-03-20 10:27:30 +00001149#if CLG_MICROSYSTIME
1150 struct vki_timeval tv_now;
1151 ULong diff;
1152
1153 VG_(do_syscall)(__NR_gettimeofday, (UInt)&tv_now, (UInt)NULL);
1154 diff = (tv_now.tv_sec * 1000000ULL + tv_now.tv_usec) - syscalltime[tid];
1155#else
1156 UInt diff = VG_(read_millisecond_timer)() - syscalltime[tid];
1157#endif
weidendo5bba5252010-06-09 22:32:53 +00001158
1159 /* offset o is for "SysCount", o+1 for "SysTime" */
1160 o = fullOffset(EG_SYS);
1161 CLG_ASSERT(o>=0);
weidendoa17f2a32006-03-20 10:27:30 +00001162 CLG_DEBUG(0," Time (Off %d) for Syscall %d: %ull\n", o, syscallno, diff);
1163
weidendoa17f2a32006-03-20 10:27:30 +00001164 CLG_(current_state).cost[o] ++;
1165 CLG_(current_state).cost[o+1] += diff;
1166 if (!CLG_(current_state).bbcc->skipped)
1167 CLG_(init_cost_lz)(CLG_(sets).full,
1168 &(CLG_(current_state).bbcc->skipped));
1169 CLG_(current_state).bbcc->skipped[o] ++;
1170 CLG_(current_state).bbcc->skipped[o+1] += diff;
1171 }
1172}
1173
1174static
1175void finish(void)
1176{
1177 char buf[RESULTS_BUF_LEN];
1178
1179 CLG_DEBUG(0, "finish()\n");
1180
1181 (*CLG_(cachesim).finish)();
1182
1183 /* pop all remaining items from CallStack for correct sum
1184 */
1185 CLG_(forall_threads)(unwind_thread);
sewardje45a7992006-10-17 02:24:18 +00001186
weidendoa17f2a32006-03-20 10:27:30 +00001187 CLG_(dump_profile)(0, False);
sewardje45a7992006-10-17 02:24:18 +00001188
weidendoa17f2a32006-03-20 10:27:30 +00001189 CLG_(finish_command)();
sewardje45a7992006-10-17 02:24:18 +00001190
weidendoa17f2a32006-03-20 10:27:30 +00001191 if (VG_(clo_verbosity) == 0) return;
1192
1193 /* Hash table stats */
sewardj2d9e8742009-08-07 15:46:56 +00001194 if (VG_(clo_stats)) {
weidendoa17f2a32006-03-20 10:27:30 +00001195 int BB_lookups =
1196 CLG_(stat).full_debug_BBs +
1197 CLG_(stat).fn_name_debug_BBs +
1198 CLG_(stat).file_line_debug_BBs +
1199 CLG_(stat).no_debug_BBs;
1200
sewardj0f33adf2009-07-15 14:51:03 +00001201 VG_(message)(Vg_DebugMsg, "\n");
1202 VG_(message)(Vg_DebugMsg, "Distinct objects: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001203 CLG_(stat).distinct_objs);
sewardj0f33adf2009-07-15 14:51:03 +00001204 VG_(message)(Vg_DebugMsg, "Distinct files: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001205 CLG_(stat).distinct_files);
sewardj0f33adf2009-07-15 14:51:03 +00001206 VG_(message)(Vg_DebugMsg, "Distinct fns: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001207 CLG_(stat).distinct_fns);
sewardj0f33adf2009-07-15 14:51:03 +00001208 VG_(message)(Vg_DebugMsg, "Distinct contexts:%d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001209 CLG_(stat).distinct_contexts);
sewardj0f33adf2009-07-15 14:51:03 +00001210 VG_(message)(Vg_DebugMsg, "Distinct BBs: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001211 CLG_(stat).distinct_bbs);
sewardj0f33adf2009-07-15 14:51:03 +00001212 VG_(message)(Vg_DebugMsg, "Cost entries: %d (Chunks %d)\n",
weidendoa17f2a32006-03-20 10:27:30 +00001213 CLG_(costarray_entries), CLG_(costarray_chunks));
sewardj0f33adf2009-07-15 14:51:03 +00001214 VG_(message)(Vg_DebugMsg, "Distinct BBCCs: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001215 CLG_(stat).distinct_bbccs);
sewardj0f33adf2009-07-15 14:51:03 +00001216 VG_(message)(Vg_DebugMsg, "Distinct JCCs: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001217 CLG_(stat).distinct_jccs);
sewardj0f33adf2009-07-15 14:51:03 +00001218 VG_(message)(Vg_DebugMsg, "Distinct skips: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001219 CLG_(stat).distinct_skips);
sewardj0f33adf2009-07-15 14:51:03 +00001220 VG_(message)(Vg_DebugMsg, "BB lookups: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001221 BB_lookups);
1222 if (BB_lookups>0) {
sewardj0f33adf2009-07-15 14:51:03 +00001223 VG_(message)(Vg_DebugMsg, "With full debug info:%3d%% (%d)\n",
weidendoa17f2a32006-03-20 10:27:30 +00001224 CLG_(stat).full_debug_BBs * 100 / BB_lookups,
1225 CLG_(stat).full_debug_BBs);
sewardj0f33adf2009-07-15 14:51:03 +00001226 VG_(message)(Vg_DebugMsg, "With file/line debug info:%3d%% (%d)\n",
weidendoa17f2a32006-03-20 10:27:30 +00001227 CLG_(stat).file_line_debug_BBs * 100 / BB_lookups,
1228 CLG_(stat).file_line_debug_BBs);
sewardj0f33adf2009-07-15 14:51:03 +00001229 VG_(message)(Vg_DebugMsg, "With fn name debug info:%3d%% (%d)\n",
weidendoa17f2a32006-03-20 10:27:30 +00001230 CLG_(stat).fn_name_debug_BBs * 100 / BB_lookups,
1231 CLG_(stat).fn_name_debug_BBs);
sewardj0f33adf2009-07-15 14:51:03 +00001232 VG_(message)(Vg_DebugMsg, "With no debug info:%3d%% (%d)\n",
weidendoa17f2a32006-03-20 10:27:30 +00001233 CLG_(stat).no_debug_BBs * 100 / BB_lookups,
1234 CLG_(stat).no_debug_BBs);
1235 }
sewardj0f33adf2009-07-15 14:51:03 +00001236 VG_(message)(Vg_DebugMsg, "BBCC Clones: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001237 CLG_(stat).bbcc_clones);
sewardj0f33adf2009-07-15 14:51:03 +00001238 VG_(message)(Vg_DebugMsg, "BBs Retranslated: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001239 CLG_(stat).bb_retranslations);
sewardj0f33adf2009-07-15 14:51:03 +00001240 VG_(message)(Vg_DebugMsg, "Distinct instrs: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001241 CLG_(stat).distinct_instrs);
1242 VG_(message)(Vg_DebugMsg, "");
1243
sewardj0f33adf2009-07-15 14:51:03 +00001244 VG_(message)(Vg_DebugMsg, "LRU Contxt Misses: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001245 CLG_(stat).cxt_lru_misses);
sewardj0f33adf2009-07-15 14:51:03 +00001246 VG_(message)(Vg_DebugMsg, "LRU BBCC Misses: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001247 CLG_(stat).bbcc_lru_misses);
sewardj0f33adf2009-07-15 14:51:03 +00001248 VG_(message)(Vg_DebugMsg, "LRU JCC Misses: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001249 CLG_(stat).jcc_lru_misses);
sewardj0f33adf2009-07-15 14:51:03 +00001250 VG_(message)(Vg_DebugMsg, "BBs Executed: %llu\n",
weidendoa17f2a32006-03-20 10:27:30 +00001251 CLG_(stat).bb_executions);
sewardj0f33adf2009-07-15 14:51:03 +00001252 VG_(message)(Vg_DebugMsg, "Calls: %llu\n",
weidendoa17f2a32006-03-20 10:27:30 +00001253 CLG_(stat).call_counter);
sewardj0f33adf2009-07-15 14:51:03 +00001254 VG_(message)(Vg_DebugMsg, "CondJMP followed: %llu\n",
weidendoa17f2a32006-03-20 10:27:30 +00001255 CLG_(stat).jcnd_counter);
sewardj0f33adf2009-07-15 14:51:03 +00001256 VG_(message)(Vg_DebugMsg, "Boring JMPs: %llu\n",
weidendoa17f2a32006-03-20 10:27:30 +00001257 CLG_(stat).jump_counter);
sewardj0f33adf2009-07-15 14:51:03 +00001258 VG_(message)(Vg_DebugMsg, "Recursive calls: %llu\n",
weidendoa17f2a32006-03-20 10:27:30 +00001259 CLG_(stat).rec_call_counter);
sewardj0f33adf2009-07-15 14:51:03 +00001260 VG_(message)(Vg_DebugMsg, "Returns: %llu\n",
weidendoa17f2a32006-03-20 10:27:30 +00001261 CLG_(stat).ret_counter);
1262
1263 VG_(message)(Vg_DebugMsg, "");
1264 }
1265
1266 CLG_(sprint_eventmapping)(buf, CLG_(dumpmap));
sewardj0f33adf2009-07-15 14:51:03 +00001267 VG_(message)(Vg_UserMsg, "Events : %s\n", buf);
weidendoa17f2a32006-03-20 10:27:30 +00001268 CLG_(sprint_mappingcost)(buf, CLG_(dumpmap), CLG_(total_cost));
sewardj0f33adf2009-07-15 14:51:03 +00001269 VG_(message)(Vg_UserMsg, "Collected : %s\n", buf);
1270 VG_(message)(Vg_UserMsg, "\n");
weidendoa17f2a32006-03-20 10:27:30 +00001271
1272 // if (CLG_(clo).simulate_cache)
1273 (*CLG_(cachesim).printstat)();
1274}
1275
1276
1277void CLG_(fini)(Int exitcode)
1278{
1279 finish();
1280}
1281
1282
1283/*--------------------------------------------------------------------*/
1284/*--- Setup ---*/
1285/*--------------------------------------------------------------------*/
1286
njn3e32c872006-12-24 07:51:17 +00001287static void clg_start_client_code_callback ( ThreadId tid, ULong blocks_done )
sewardj97561812006-12-23 01:21:12 +00001288{
weidendo134657c2006-12-23 23:11:20 +00001289 static ULong last_blocks_done = 0;
1290
sewardj97561812006-12-23 01:21:12 +00001291 if (0)
njn3e32c872006-12-24 07:51:17 +00001292 VG_(printf)("%d R %llu\n", (Int)tid, blocks_done);
weidendo134657c2006-12-23 23:11:20 +00001293
1294 /* throttle calls to CLG_(run_thread) by number of BBs executed */
1295 if (blocks_done - last_blocks_done < 5000) return;
1296 last_blocks_done = blocks_done;
1297
1298 CLG_(run_thread)( tid );
sewardj97561812006-12-23 01:21:12 +00001299}
1300
weidendoa17f2a32006-03-20 10:27:30 +00001301static
1302void CLG_(post_clo_init)(void)
1303{
weidendoa17f2a32006-03-20 10:27:30 +00001304 VG_(clo_vex_control).iropt_unroll_thresh = 0;
1305 VG_(clo_vex_control).guest_chase_thresh = 0;
1306
1307 CLG_DEBUG(1, " dump threads: %s\n", CLG_(clo).separate_threads ? "Yes":"No");
1308 CLG_DEBUG(1, " call sep. : %d\n", CLG_(clo).separate_callers);
1309 CLG_DEBUG(1, " rec. sep. : %d\n", CLG_(clo).separate_recursions);
1310
1311 if (!CLG_(clo).dump_line && !CLG_(clo).dump_instr && !CLG_(clo).dump_bb) {
sewardj0f33adf2009-07-15 14:51:03 +00001312 VG_(message)(Vg_UserMsg, "Using source line as position.\n");
weidendoa17f2a32006-03-20 10:27:30 +00001313 CLG_(clo).dump_line = True;
1314 }
1315
weidendo4ce5e792006-09-20 21:29:39 +00001316 CLG_(init_dumps)();
1317 CLG_(init_command)();
weidendoa17f2a32006-03-20 10:27:30 +00001318
1319 (*CLG_(cachesim).post_clo_init)();
1320
weidendo5bba5252010-06-09 22:32:53 +00001321 CLG_(init_eventsets)();
weidendoa17f2a32006-03-20 10:27:30 +00001322 CLG_(init_statistics)(& CLG_(stat));
1323 CLG_(init_cost_lz)( CLG_(sets).full, &CLG_(total_cost) );
1324
1325 /* initialize hash tables */
1326 CLG_(init_obj_table)();
1327 CLG_(init_cxt_table)();
1328 CLG_(init_bb_hash)();
1329
1330 CLG_(init_threads)();
1331 CLG_(run_thread)(1);
1332
1333 CLG_(instrument_state) = CLG_(clo).instrument_atstart;
1334
weidendoca472c52006-03-31 19:34:51 +00001335 if (VG_(clo_verbosity > 0)) {
weidendoca472c52006-03-31 19:34:51 +00001336 VG_(message)(Vg_UserMsg,
sewardj0f33adf2009-07-15 14:51:03 +00001337 "For interactive control, run 'callgrind_control -h'.\n");
weidendoca472c52006-03-31 19:34:51 +00001338 }
weidendoa17f2a32006-03-20 10:27:30 +00001339}
1340
1341static
1342void CLG_(pre_clo_init)(void)
1343{
1344 VG_(details_name) ("Callgrind");
weidendoca472c52006-03-31 19:34:51 +00001345 VG_(details_version) (NULL);
weidendoa17f2a32006-03-20 10:27:30 +00001346 VG_(details_description) ("a call-graph generating cache profiler");
sewardj9eecbbb2010-05-03 21:37:12 +00001347 VG_(details_copyright_author)("Copyright (C) 2002-2010, and GNU GPL'd, "
weidendoca472c52006-03-31 19:34:51 +00001348 "by Josef Weidendorfer et al.");
weidendodb70ed72006-05-27 15:39:45 +00001349 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardje45a7992006-10-17 02:24:18 +00001350 VG_(details_avg_translation_sizeB) ( 500 );
weidendoa17f2a32006-03-20 10:27:30 +00001351
1352 VG_(basic_tool_funcs) (CLG_(post_clo_init),
1353 CLG_(instrument),
1354 CLG_(fini));
1355
sewardj0b9d74a2006-12-24 02:24:11 +00001356 VG_(needs_superblock_discards)(clg_discard_superblock_info);
weidendoa17f2a32006-03-20 10:27:30 +00001357
1358
1359 VG_(needs_command_line_options)(CLG_(process_cmd_line_option),
1360 CLG_(print_usage),
1361 CLG_(print_debug_usage));
1362
1363 VG_(needs_client_requests)(CLG_(handle_client_request));
1364 VG_(needs_syscall_wrapper)(CLG_(pre_syscalltime),
1365 CLG_(post_syscalltime));
1366
njn3e32c872006-12-24 07:51:17 +00001367 VG_(track_start_client_code) ( & clg_start_client_code_callback );
1368 VG_(track_pre_deliver_signal) ( & CLG_(pre_signal) );
1369 VG_(track_post_deliver_signal)( & CLG_(post_signal) );
weidendoa17f2a32006-03-20 10:27:30 +00001370
1371 CLG_(set_clo_defaults)();
1372}
1373
1374VG_DETERMINE_INTERFACE_VERSION(CLG_(pre_clo_init))
1375
1376/*--------------------------------------------------------------------*/
1377/*--- end main.c ---*/
1378/*--------------------------------------------------------------------*/