blob: 147e6d05562533b74a4c5636641521659eb73675 [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
njn9f207462009-03-10 22:02:09 +000011 Copyright (C) 2002-2009, 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
njn9f207462009-03-10 22:02:09 +000014 Copyright (C) 2002-2009 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);
276 ev->inode->eventset = CLG_(sets).UIr;
277 break;
278 case Ev_Dr:
279 // extend event set by Dr counter
280 if ((ev->inode->eventset == CLG_(sets).UIrDr) ||
281 (ev->inode->eventset == CLG_(sets).UIrDrDw) ||
282 (ev->inode->eventset == CLG_(sets).UIrDwDr))
283 break;
284 if (ev->inode->eventset == CLG_(sets).UIrDw) {
285 ev->inode->eventset = CLG_(sets).UIrDwDr;
286 break;
287 }
288 CLG_ASSERT(ev->inode->eventset == CLG_(sets).UIr);
289 ev->inode->eventset = CLG_(sets).UIrDr;
290 break;
291 case Ev_Dw:
292 case Ev_Dm:
293 // extend event set by Dw counter
294 if ((ev->inode->eventset == CLG_(sets).UIrDw) ||
295 (ev->inode->eventset == CLG_(sets).UIrDwDr) ||
296 (ev->inode->eventset == CLG_(sets).UIrDrDw))
297 break;
298 if (ev->inode->eventset == CLG_(sets).UIrDr) {
299 ev->inode->eventset = CLG_(sets).UIrDrDw;
300 break;
301 }
302 CLG_ASSERT(ev->inode->eventset == CLG_(sets).UIr);
303 ev->inode->eventset = CLG_(sets).UIrDw;
304 break;
305 default:
306 tl_assert(0);
307 }
308 }
309 }
310
311 for(i = 0; i < clgs->events_used; i = inew) {
312
313 helperName = NULL;
314 helperAddr = NULL;
315 argv = NULL;
316 regparms = 0;
317
318 /* generate IR to notify event i and possibly the ones
319 immediately following it. */
320 tl_assert(i >= 0 && i < clgs->events_used);
321
322 ev = &clgs->events[i];
323 ev2 = ( i < clgs->events_used-1 ? &clgs->events[i+1] : NULL );
324 ev3 = ( i < clgs->events_used-2 ? &clgs->events[i+2] : NULL );
325
326 CLG_DEBUGIF(5) {
327 VG_(printf)(" flush ");
328 showEvent( ev );
329 }
330
331 i_node_expr = mkIRExpr_HWord( (HWord)ev->inode );
332
333 /* Decide on helper fn to call and args to pass it, and advance
334 i appropriately.
335 Dm events have same effect as Dw events */
336 switch (ev->tag) {
337 case Ev_Ir:
338 /* Merge an Ir with a following Dr. */
339 if (ev2 && ev2->tag == Ev_Dr) {
340 /* Why is this true? It's because we're merging an Ir
341 with a following Dr. The Ir derives from the
342 instruction's IMark and the Dr from data
343 references which follow it. In short it holds
344 because each insn starts with an IMark, hence an
345 Ev_Ir, and so these Dr must pertain to the
346 immediately preceding Ir. Same applies to analogous
347 assertions in the subsequent cases. */
348 tl_assert(ev2->inode == ev->inode);
349 helperName = CLG_(cachesim).log_1I1Dr_name;
350 helperAddr = CLG_(cachesim).log_1I1Dr;
351 argv = mkIRExprVec_3( i_node_expr,
352 get_Event_dea(ev2),
353 mkIRExpr_HWord( get_Event_dszB(ev2) ) );
354 regparms = 3;
355 inew = i+2;
356 }
357 /* Merge an Ir with a following Dw/Dm. */
358 else
359 if (ev2 && (ev2->tag == Ev_Dw || ev2->tag == Ev_Dm)) {
360 tl_assert(ev2->inode == ev->inode);
361 helperName = CLG_(cachesim).log_1I1Dw_name;
362 helperAddr = CLG_(cachesim).log_1I1Dw;
363 argv = mkIRExprVec_3( i_node_expr,
364 get_Event_dea(ev2),
365 mkIRExpr_HWord( get_Event_dszB(ev2) ) );
366 regparms = 3;
367 inew = i+2;
368 }
369 /* Merge an Ir with two following Irs. */
370 else
371 if (ev2 && ev3 && ev2->tag == Ev_Ir && ev3->tag == Ev_Ir) {
372 helperName = CLG_(cachesim).log_3I0D_name;
373 helperAddr = CLG_(cachesim).log_3I0D;
374 argv = mkIRExprVec_3( i_node_expr,
375 mkIRExpr_HWord( (HWord)ev2->inode ),
376 mkIRExpr_HWord( (HWord)ev3->inode ) );
377 regparms = 3;
378 inew = i+3;
379 }
380 /* Merge an Ir with one following Ir. */
381 else
382 if (ev2 && ev2->tag == Ev_Ir) {
383 helperName = CLG_(cachesim).log_2I0D_name;
384 helperAddr = CLG_(cachesim).log_2I0D;
385 argv = mkIRExprVec_2( i_node_expr,
386 mkIRExpr_HWord( (HWord)ev2->inode ) );
387 regparms = 2;
388 inew = i+2;
389 }
390 /* No merging possible; emit as-is. */
391 else {
392 helperName = CLG_(cachesim).log_1I0D_name;
393 helperAddr = CLG_(cachesim).log_1I0D;
394 argv = mkIRExprVec_1( i_node_expr );
395 regparms = 1;
396 inew = i+1;
397 }
398 break;
399 case Ev_Dr:
400 /* Data read or modify */
weidendoa17f2a32006-03-20 10:27:30 +0000401 helperName = CLG_(cachesim).log_0I1Dr_name;
402 helperAddr = CLG_(cachesim).log_0I1Dr;
weidendo0a1951d2009-06-15 00:16:36 +0000403 argv = mkIRExprVec_3( i_node_expr,
404 get_Event_dea(ev),
405 mkIRExpr_HWord( get_Event_dszB(ev) ) );
406 regparms = 3;
407 inew = i+1;
408 break;
409 case Ev_Dw:
410 case Ev_Dm:
411 /* Data write */
weidendoa17f2a32006-03-20 10:27:30 +0000412 helperName = CLG_(cachesim).log_0I1Dw_name;
413 helperAddr = CLG_(cachesim).log_0I1Dw;
weidendo0a1951d2009-06-15 00:16:36 +0000414 argv = mkIRExprVec_3( i_node_expr,
415 get_Event_dea(ev),
416 mkIRExpr_HWord( get_Event_dszB(ev) ) );
417 regparms = 3;
418 inew = i+1;
419 break;
420 default:
421 tl_assert(0);
422 }
weidendoa17f2a32006-03-20 10:27:30 +0000423
weidendo0a1951d2009-06-15 00:16:36 +0000424 CLG_DEBUGIF(5) {
425 if (inew > i+1) {
426 VG_(printf)(" merge ");
427 showEvent( ev2 );
428 }
429 if (inew > i+2) {
430 VG_(printf)(" merge ");
431 showEvent( ev3 );
432 }
433 if (helperAddr)
434 VG_(printf)(" call %s (%p)\n",
435 helperName, helperAddr);
436 }
weidendoa17f2a32006-03-20 10:27:30 +0000437
weidendo0a1951d2009-06-15 00:16:36 +0000438 /* helper could be unset depending on the simulator used */
439 if (helperAddr == 0) continue;
weidendoa17f2a32006-03-20 10:27:30 +0000440
weidendo0a1951d2009-06-15 00:16:36 +0000441 /* Add the helper. */
442 tl_assert(helperName);
443 tl_assert(helperAddr);
444 tl_assert(argv);
445 di = unsafeIRDirty_0_N( regparms,
446 helperName, VG_(fnptr_to_fnentry)( helperAddr ),
447 argv );
448 addStmtToIRSB( clgs->sbOut, IRStmt_Dirty(di) );
weidendoa17f2a32006-03-20 10:27:30 +0000449 }
450
weidendo0a1951d2009-06-15 00:16:36 +0000451 clgs->events_used = 0;
452}
weidendoa17f2a32006-03-20 10:27:30 +0000453
weidendo0a1951d2009-06-15 00:16:36 +0000454static void addEvent_Ir ( ClgState* clgs, InstrInfo* inode )
455{
456 Event* evt;
457 tl_assert(clgs->seen_before || (inode->eventset == 0));
458 if (!CLG_(clo).simulate_cache) return;
weidendoa17f2a32006-03-20 10:27:30 +0000459
weidendo0a1951d2009-06-15 00:16:36 +0000460 if (clgs->events_used == N_EVENTS)
461 flushEvents(clgs);
462 tl_assert(clgs->events_used >= 0 && clgs->events_used < N_EVENTS);
463 evt = &clgs->events[clgs->events_used];
464 init_Event(evt);
465 evt->tag = Ev_Ir;
466 evt->inode = inode;
467 clgs->events_used++;
468}
weidendoa17f2a32006-03-20 10:27:30 +0000469
weidendo0a1951d2009-06-15 00:16:36 +0000470static
471void addEvent_Dr ( ClgState* clgs, InstrInfo* inode, Int datasize, IRAtom* ea )
472{
473 Event* evt;
474 tl_assert(isIRAtom(ea));
475 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
476 if (!CLG_(clo).simulate_cache) return;
weidendoc8e76152006-05-27 15:30:58 +0000477
weidendo0a1951d2009-06-15 00:16:36 +0000478 if (clgs->events_used == N_EVENTS)
479 flushEvents(clgs);
480 tl_assert(clgs->events_used >= 0 && clgs->events_used < N_EVENTS);
481 evt = &clgs->events[clgs->events_used];
482 init_Event(evt);
483 evt->tag = Ev_Dr;
484 evt->inode = inode;
485 evt->Ev.Dr.szB = datasize;
486 evt->Ev.Dr.ea = ea;
487 clgs->events_used++;
488}
weidendoc8e76152006-05-27 15:30:58 +0000489
weidendo0a1951d2009-06-15 00:16:36 +0000490static
491void addEvent_Dw ( ClgState* clgs, InstrInfo* inode, Int datasize, IRAtom* ea )
492{
493 Event* lastEvt;
494 Event* evt;
495 tl_assert(isIRAtom(ea));
496 tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE);
497 if (!CLG_(clo).simulate_cache) return;
weidendoc8e76152006-05-27 15:30:58 +0000498
weidendo0a1951d2009-06-15 00:16:36 +0000499 /* Is it possible to merge this write with the preceding read? */
500 lastEvt = &clgs->events[clgs->events_used-1];
501 if (clgs->events_used > 0
502 && lastEvt->tag == Ev_Dr
503 && lastEvt->Ev.Dr.szB == datasize
504 && lastEvt->inode == inode
505 && eqIRAtom(lastEvt->Ev.Dr.ea, ea))
506 {
507 lastEvt->tag = Ev_Dm;
508 return;
509 }
weidendoc8e76152006-05-27 15:30:58 +0000510
weidendo0a1951d2009-06-15 00:16:36 +0000511 /* No. Add as normal. */
512 if (clgs->events_used == N_EVENTS)
513 flushEvents(clgs);
514 tl_assert(clgs->events_used >= 0 && clgs->events_used < N_EVENTS);
515 evt = &clgs->events[clgs->events_used];
516 init_Event(evt);
517 evt->tag = Ev_Dw;
518 evt->inode = inode;
519 evt->Ev.Dw.szB = datasize;
520 evt->Ev.Dw.ea = ea;
521 clgs->events_used++;
522}
523
524/* Initialise or check (if already seen before) an InstrInfo for next insn.
525 We only can set instr_offset/instr_size here. The required event set and
526 resulting cost offset depend on events (Ir/Dr/Dw/Dm) in guest
527 instructions. The event set is extended as required on flush of the event
528 queue (when Dm events were determined), cost offsets are determined at
529 end of BB instrumentation. */
530static
531InstrInfo* next_InstrInfo ( ClgState* clgs, UInt instr_size )
532{
533 InstrInfo* ii;
534 tl_assert(clgs->ii_index >= 0);
535 tl_assert(clgs->ii_index < clgs->bb->instr_count);
536 ii = &clgs->bb->instr[ clgs->ii_index ];
537
538 if (clgs->seen_before) {
539 CLG_ASSERT(ii->instr_offset == clgs->instr_offset);
540 CLG_ASSERT(ii->instr_size == instr_size);
weidendoa17f2a32006-03-20 10:27:30 +0000541 }
542 else {
weidendo0a1951d2009-06-15 00:16:36 +0000543 ii->instr_offset = clgs->instr_offset;
544 ii->instr_size = instr_size;
545 ii->cost_offset = 0;
546 ii->eventset = 0;
weidendoa17f2a32006-03-20 10:27:30 +0000547 }
548
weidendo0a1951d2009-06-15 00:16:36 +0000549 clgs->ii_index++;
550 clgs->instr_offset += instr_size;
551 CLG_(stat).distinct_instrs++;
weidendoa17f2a32006-03-20 10:27:30 +0000552
weidendo0a1951d2009-06-15 00:16:36 +0000553 return ii;
weidendoa17f2a32006-03-20 10:27:30 +0000554}
555
weidendo0a1951d2009-06-15 00:16:36 +0000556// return total number of cost values needed for this BB
557static
558UInt update_cost_offsets( ClgState* clgs )
559{
560 Int i;
561 InstrInfo* ii;
562 UInt cost_offset = 0;
563
564 CLG_ASSERT(clgs->bb->instr_count == clgs->ii_index);
565 for(i=0; i<clgs->ii_index; i++) {
566 ii = &clgs->bb->instr[i];
567 if (clgs->seen_before) {
568 CLG_ASSERT(ii->cost_offset == cost_offset);
569 } else
570 ii->cost_offset = cost_offset;
571 cost_offset += ii->eventset ? ii->eventset->size : 0;
572 }
573
574 return cost_offset;
575}
576
577/*------------------------------------------------------------*/
578/*--- Instrumentation ---*/
579/*------------------------------------------------------------*/
580
weidendoa17f2a32006-03-20 10:27:30 +0000581#if defined(VG_BIGENDIAN)
582# define CLGEndness Iend_BE
583#elif defined(VG_LITTLEENDIAN)
584# define CLGEndness Iend_LE
585#else
586# error "Unknown endianness"
587#endif
588
589static
590Addr IRConst2Addr(IRConst* con)
591{
592 Addr addr;
593
594 if (sizeof(Addr) == 4) {
595 CLG_ASSERT( con->tag == Ico_U32 );
596 addr = con->Ico.U32;
597 }
598 else if (sizeof(Addr) == 8) {
599 CLG_ASSERT( con->tag == Ico_U64 );
600 addr = con->Ico.U64;
601 }
602 else
603 VG_(tool_panic)("Callgrind: invalid Addr type");
604
605 return addr;
606}
607
608/* First pass over a BB to instrument, counting instructions and jumps
609 * This is needed for the size of the BB struct to allocate
610 *
611 * Called from CLG_(get_bb)
612 */
weidendo0a1951d2009-06-15 00:16:36 +0000613void CLG_(collectBlockInfo)(IRSB* sbIn,
weidendoa17f2a32006-03-20 10:27:30 +0000614 /*INOUT*/ UInt* instrs,
615 /*INOUT*/ UInt* cjmps,
616 /*INOUT*/ Bool* cjmp_inverted)
617{
618 Int i;
619 IRStmt* st;
620 Addr instrAddr =0, jumpDst;
621 UInt instrLen = 0;
622 Bool toNextInstr = False;
623
624 // Ist_Exit has to be ignored in preamble code, before first IMark:
625 // preamble code is added by VEX for self modifying code, and has
626 // nothing to do with client code
627 Bool inPreamble = True;
628
weidendo0a1951d2009-06-15 00:16:36 +0000629 if (!sbIn) return;
weidendoa17f2a32006-03-20 10:27:30 +0000630
weidendo0a1951d2009-06-15 00:16:36 +0000631 for (i = 0; i < sbIn->stmts_used; i++) {
632 st = sbIn->stmts[i];
weidendoa17f2a32006-03-20 10:27:30 +0000633 if (Ist_IMark == st->tag) {
634 inPreamble = False;
635
636 instrAddr = (Addr)ULong_to_Ptr(st->Ist.IMark.addr);
637 instrLen = st->Ist.IMark.len;
638
639 (*instrs)++;
640 toNextInstr = False;
641 }
642 if (inPreamble) continue;
643 if (Ist_Exit == st->tag) {
644 jumpDst = IRConst2Addr(st->Ist.Exit.dst);
645 toNextInstr = (jumpDst == instrAddr + instrLen);
weidendo0a1951d2009-06-15 00:16:36 +0000646
weidendoa17f2a32006-03-20 10:27:30 +0000647 (*cjmps)++;
648 }
649 }
650
651 /* if the last instructions of BB conditionally jumps to next instruction
652 * (= first instruction of next BB in memory), this is a inverted by VEX.
653 */
654 *cjmp_inverted = toNextInstr;
655}
656
657static
sewardj0b9d74a2006-12-24 02:24:11 +0000658void addConstMemStoreStmt( IRSB* bbOut, UWord addr, UInt val, IRType hWordTy)
weidendoa17f2a32006-03-20 10:27:30 +0000659{
sewardj0b9d74a2006-12-24 02:24:11 +0000660 addStmtToIRSB( bbOut,
weidendoa17f2a32006-03-20 10:27:30 +0000661 IRStmt_Store(CLGEndness,
662 IRExpr_Const(hWordTy == Ity_I32 ?
663 IRConst_U32( addr ) :
664 IRConst_U64( addr )),
665 IRExpr_Const(IRConst_U32(val)) ));
666}
667
weidendo0a1951d2009-06-15 00:16:36 +0000668
669/* add helper call to setup_bbcc, with pointer to BB struct as argument
670 *
671 * precondition for setup_bbcc:
672 * - jmps_passed has number of cond.jumps passed in last executed BB
673 * - current_bbcc has a pointer to the BBCC of the last executed BB
674 * Thus, if bbcc_jmpkind is != -1 (JmpNone),
675 * current_bbcc->bb->jmp_addr
676 * gives the address of the jump source.
677 *
678 * the setup does 2 things:
679 * - trace call:
680 * * Unwind own call stack, i.e sync our ESP with real ESP
681 * This is for ESP manipulation (longjmps, C++ exec handling) and RET
682 * * For CALLs or JMPs crossing objects, record call arg +
683 * push are on own call stack
684 *
685 * - prepare for cache log functions:
686 * set current_bbcc to BBCC that gets the costs for this BB execution
687 * attached
688 */
689static
690void addBBSetupCall(ClgState* clgs)
691{
692 IRDirty* di;
693 IRExpr *arg1, **argv;
694
695 arg1 = mkIRExpr_HWord( (HWord)clgs->bb );
696 argv = mkIRExprVec_1(arg1);
697 di = unsafeIRDirty_0_N( 1, "setup_bbcc",
698 VG_(fnptr_to_fnentry)( & CLG_(setup_bbcc) ),
699 argv);
700 addStmtToIRSB( clgs->sbOut, IRStmt_Dirty(di) );
701}
702
703
weidendoa17f2a32006-03-20 10:27:30 +0000704static
sewardj0b9d74a2006-12-24 02:24:11 +0000705IRSB* CLG_(instrument)( VgCallbackClosure* closure,
weidendo0a1951d2009-06-15 00:16:36 +0000706 IRSB* sbIn,
weidendoa17f2a32006-03-20 10:27:30 +0000707 VexGuestLayout* layout,
708 VexGuestExtents* vge,
709 IRType gWordTy, IRType hWordTy )
710{
weidendo0a1951d2009-06-15 00:16:36 +0000711 Int i, isize;
712 IRStmt* st;
713 Addr origAddr;
714 InstrInfo* curr_inode = NULL;
715 ClgState clgs;
716 UInt cJumps = 0;
weidendoa17f2a32006-03-20 10:27:30 +0000717
weidendoa17f2a32006-03-20 10:27:30 +0000718
719 if (gWordTy != hWordTy) {
720 /* We don't currently support this case. */
721 VG_(tool_panic)("host/guest word size mismatch");
722 }
723
724 // No instrumentation if it is switched off
725 if (! CLG_(instrument_state)) {
barta0b6b2c2008-07-07 06:49:24 +0000726 CLG_DEBUG(5, "instrument(BB %#lx) [Instrumentation OFF]\n",
weidendoa17f2a32006-03-20 10:27:30 +0000727 (Addr)closure->readdr);
weidendo0a1951d2009-06-15 00:16:36 +0000728 return sbIn;
weidendoa17f2a32006-03-20 10:27:30 +0000729 }
730
barta0b6b2c2008-07-07 06:49:24 +0000731 CLG_DEBUG(3, "+ instrument(BB %#lx)\n", (Addr)closure->readdr);
weidendoa17f2a32006-03-20 10:27:30 +0000732
sewardj0b9d74a2006-12-24 02:24:11 +0000733 /* Set up SB for instrumented IR */
weidendo0a1951d2009-06-15 00:16:36 +0000734 clgs.sbOut = deepCopyIRSBExceptStmts(sbIn);
weidendoa17f2a32006-03-20 10:27:30 +0000735
736 // Copy verbatim any IR preamble preceding the first IMark
737 i = 0;
weidendo0a1951d2009-06-15 00:16:36 +0000738 while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
739 addStmtToIRSB( clgs.sbOut, sbIn->stmts[i] );
weidendoa17f2a32006-03-20 10:27:30 +0000740 i++;
741 }
742
743 // Get the first statement, and origAddr from it
weidendo0a1951d2009-06-15 00:16:36 +0000744 CLG_ASSERT(sbIn->stmts_used >0);
745 CLG_ASSERT(i < sbIn->stmts_used);
746 st = sbIn->stmts[i];
weidendoa17f2a32006-03-20 10:27:30 +0000747 CLG_ASSERT(Ist_IMark == st->tag);
weidendo0a1951d2009-06-15 00:16:36 +0000748
749 origAddr = (Addr)st->Ist.IMark.addr;
weidendoa17f2a32006-03-20 10:27:30 +0000750 CLG_ASSERT(origAddr == st->Ist.IMark.addr); // XXX: check no overflow
751
weidendo0a1951d2009-06-15 00:16:36 +0000752 /* Get BB struct (creating if necessary).
weidendoa17f2a32006-03-20 10:27:30 +0000753 * JS: The hash table is keyed with orig_addr_noredir -- important!
754 * JW: Why? If it is because of different chasing of the redirection,
755 * this is not needed, as chasing is switched off in callgrind
756 */
weidendo0a1951d2009-06-15 00:16:36 +0000757 clgs.bb = CLG_(get_bb)(origAddr, sbIn, &(clgs.seen_before));
weidendoa17f2a32006-03-20 10:27:30 +0000758
weidendo0a1951d2009-06-15 00:16:36 +0000759 addBBSetupCall(&clgs);
weidendoa17f2a32006-03-20 10:27:30 +0000760
weidendo0a1951d2009-06-15 00:16:36 +0000761 // Set up running state
762 clgs.events_used = 0;
763 clgs.ii_index = 0;
764 clgs.instr_offset = 0;
weidendoa17f2a32006-03-20 10:27:30 +0000765
weidendo0a1951d2009-06-15 00:16:36 +0000766 for (/*use current i*/; i < sbIn->stmts_used; i++) {
weidendoa17f2a32006-03-20 10:27:30 +0000767
weidendo0a1951d2009-06-15 00:16:36 +0000768 st = sbIn->stmts[i];
769 CLG_ASSERT(isFlatIRStmt(st));
weidendoa17f2a32006-03-20 10:27:30 +0000770
weidendo0a1951d2009-06-15 00:16:36 +0000771 switch (st->tag) {
772 case Ist_NoOp:
773 case Ist_AbiHint:
774 case Ist_Put:
775 case Ist_PutI:
776 case Ist_MBE:
777 break;
weidendoa17f2a32006-03-20 10:27:30 +0000778
weidendo0a1951d2009-06-15 00:16:36 +0000779 case Ist_IMark: {
780 CLG_ASSERT(clgs.instr_offset == (Addr)st->Ist.IMark.addr - origAddr);
781 isize = st->Ist.IMark.len;
782 // If Vex fails to decode an instruction, the size will be zero.
783 // Pretend otherwise.
784 if (isize == 0) isize = VG_MIN_INSTR_SZB;
weidendoa17f2a32006-03-20 10:27:30 +0000785
weidendo0a1951d2009-06-15 00:16:36 +0000786 // Sanity-check size.
787 tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
788 || VG_CLREQ_SZB == isize );
weidendoa17f2a32006-03-20 10:27:30 +0000789
weidendo0a1951d2009-06-15 00:16:36 +0000790 // Init the inode, record it as the current one.
791 // Subsequent Dr/Dw/Dm events from the same instruction will
792 // also use it.
793 curr_inode = next_InstrInfo (&clgs, isize);
weidendoa17f2a32006-03-20 10:27:30 +0000794
weidendo0a1951d2009-06-15 00:16:36 +0000795 addEvent_Ir( &clgs, curr_inode );
796 break;
797 }
weidendoa17f2a32006-03-20 10:27:30 +0000798
weidendo0a1951d2009-06-15 00:16:36 +0000799 case Ist_WrTmp: {
800 IRExpr* data = st->Ist.WrTmp.data;
801 if (data->tag == Iex_Load) {
802 IRExpr* aexpr = data->Iex.Load.addr;
803 // Note also, endianness info is ignored. I guess
804 // that's not interesting.
805 addEvent_Dr( &clgs, curr_inode,
806 sizeofIRType(data->Iex.Load.ty), aexpr );
807 }
808 break;
809 }
weidendoa17f2a32006-03-20 10:27:30 +0000810
weidendo0a1951d2009-06-15 00:16:36 +0000811 case Ist_Store: {
812 IRExpr* data = st->Ist.Store.data;
813 IRExpr* aexpr = st->Ist.Store.addr;
814 addEvent_Dw( &clgs, curr_inode,
815 sizeofIRType(typeOfIRExpr(sbIn->tyenv, data)), aexpr );
816 break;
817 }
weidendoa17f2a32006-03-20 10:27:30 +0000818
weidendo0a1951d2009-06-15 00:16:36 +0000819 case Ist_Dirty: {
820 Int dataSize;
821 IRDirty* d = st->Ist.Dirty.details;
822 if (d->mFx != Ifx_None) {
823 /* This dirty helper accesses memory. Collect the details. */
824 tl_assert(d->mAddr != NULL);
825 tl_assert(d->mSize != 0);
826 dataSize = d->mSize;
827 // Large (eg. 28B, 108B, 512B on x86) data-sized
828 // instructions will be done inaccurately, but they're
829 // very rare and this avoids errors from hitting more
830 // than two cache lines in the simulation.
831 if (dataSize > MIN_LINE_SIZE)
832 dataSize = MIN_LINE_SIZE;
833 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
834 addEvent_Dr( &clgs, curr_inode, dataSize, d->mAddr );
835 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
836 addEvent_Dw( &clgs, curr_inode, dataSize, d->mAddr );
837 } else {
838 tl_assert(d->mAddr == NULL);
839 tl_assert(d->mSize == 0);
840 }
841 break;
842 }
weidendoa17f2a32006-03-20 10:27:30 +0000843
sewardj1c0ce7a2009-07-01 08:10:49 +0000844 case Ist_CAS: {
845 /* We treat it as a read and a write of the location. I
846 think that is the same behaviour as it was before IRCAS
847 was introduced, since prior to that point, the Vex
848 front ends would translate a lock-prefixed instruction
849 into a (normal) read followed by a (normal) write. */
850 Int dataSize;
851 IRCAS* cas = st->Ist.CAS.details;
852 CLG_ASSERT(cas->addr && isIRAtom(cas->addr));
853 CLG_ASSERT(cas->dataLo);
854 dataSize = sizeofIRType(typeOfIRExpr(sbIn->tyenv, cas->dataLo));
855 if (cas->dataHi != NULL)
856 dataSize *= 2; /* since this is a doubleword-cas */
857 addEvent_Dr( &clgs, curr_inode, dataSize, cas->addr );
858 addEvent_Dw( &clgs, curr_inode, dataSize, cas->addr );
859 break;
860 }
sewardjdb5907d2009-11-26 17:20:21 +0000861
862 case Ist_LLSC: {
863 IRType dataTy;
864 if (st->Ist.LLSC.storedata == NULL) {
865 /* LL */
866 dataTy = typeOfIRTemp(sbIn->tyenv, st->Ist.LLSC.result);
867 addEvent_Dr( &clgs, curr_inode,
868 sizeofIRType(dataTy), st->Ist.LLSC.addr );
869 } else {
870 /* SC */
871 dataTy = typeOfIRExpr(sbIn->tyenv, st->Ist.LLSC.storedata);
872 addEvent_Dw( &clgs, curr_inode,
873 sizeofIRType(dataTy), st->Ist.LLSC.addr );
874 }
875 break;
876 }
877
878 case Ist_Exit: {
weidendo0a1951d2009-06-15 00:16:36 +0000879 UInt jmps_passed;
weidendoa17f2a32006-03-20 10:27:30 +0000880
weidendo0a1951d2009-06-15 00:16:36 +0000881 /* We may never reach the next statement, so need to flush
882 all outstanding transactions now. */
883 flushEvents( &clgs );
weidendoa17f2a32006-03-20 10:27:30 +0000884
weidendo0a1951d2009-06-15 00:16:36 +0000885 CLG_ASSERT(clgs.ii_index>0);
886 if (!clgs.seen_before) {
887 clgs.bb->jmp[cJumps].instr = clgs.ii_index-1;
888 clgs.bb->jmp[cJumps].skip = False;
889 }
890
891 /* Update global variable jmps_passed before the jump
892 * A correction is needed if VEX inverted the last jump condition
893 */
894 jmps_passed = cJumps;
895 if ((cJumps+1 == clgs.bb->cjmp_count) && clgs.bb->cjmp_inverted)
896 jmps_passed++;
897 addConstMemStoreStmt( clgs.sbOut,
898 (UWord) &CLG_(current_state).jmps_passed,
899 jmps_passed, hWordTy);
900 cJumps++;
901
902 break;
903 }
904
905 default:
906 tl_assert(0);
907 break;
908 }
909
910 /* Copy the original statement */
911 addStmtToIRSB( clgs.sbOut, st );
912
913 CLG_DEBUGIF(5) {
914 VG_(printf)(" pass ");
915 ppIRStmt(st);
916 VG_(printf)("\n");
917 }
weidendoa17f2a32006-03-20 10:27:30 +0000918 }
weidendoa17f2a32006-03-20 10:27:30 +0000919
weidendo0a1951d2009-06-15 00:16:36 +0000920 /* At the end of the bb. Flush outstandings. */
921 flushEvents( &clgs );
922
923 /* Always update global variable jmps_passed at end of bb.
weidendoa17f2a32006-03-20 10:27:30 +0000924 * A correction is needed if VEX inverted the last jump condition
925 */
weidendo0a1951d2009-06-15 00:16:36 +0000926 {
927 UInt jmps_passed = cJumps;
928 if (clgs.bb->cjmp_inverted) jmps_passed--;
929 addConstMemStoreStmt( clgs.sbOut,
930 (UWord) &CLG_(current_state).jmps_passed,
931 jmps_passed, hWordTy);
932 }
933 CLG_ASSERT(clgs.bb->cjmp_count == cJumps);
934 CLG_ASSERT(clgs.bb->instr_count = clgs.ii_index);
weidendoa17f2a32006-03-20 10:27:30 +0000935
936 /* This stores the instr of the call/ret at BB end */
weidendo0a1951d2009-06-15 00:16:36 +0000937 clgs.bb->jmp[cJumps].instr = clgs.ii_index-1;
weidendoa17f2a32006-03-20 10:27:30 +0000938
weidendo0a1951d2009-06-15 00:16:36 +0000939 if (clgs.seen_before) {
940 CLG_ASSERT(clgs.bb->cost_count == update_cost_offsets(&clgs));
941 CLG_ASSERT(clgs.bb->instr_len = clgs.instr_offset);
942 CLG_ASSERT(clgs.bb->jmpkind == sbIn->jumpkind);
weidendoa17f2a32006-03-20 10:27:30 +0000943 }
944 else {
weidendo0a1951d2009-06-15 00:16:36 +0000945 clgs.bb->cost_count = update_cost_offsets(&clgs);
946 clgs.bb->instr_len = clgs.instr_offset;
947 clgs.bb->jmpkind = sbIn->jumpkind;
weidendoa17f2a32006-03-20 10:27:30 +0000948 }
weidendo0a1951d2009-06-15 00:16:36 +0000949
barta0b6b2c2008-07-07 06:49:24 +0000950 CLG_DEBUG(3, "- instrument(BB %#lx): byteLen %u, CJumps %u, CostLen %u\n",
weidendo0a1951d2009-06-15 00:16:36 +0000951 origAddr, clgs.bb->instr_len,
952 clgs.bb->cjmp_count, clgs.bb->cost_count);
weidendoa17f2a32006-03-20 10:27:30 +0000953 if (cJumps>0) {
954 CLG_DEBUG(3, " [ ");
955 for (i=0;i<cJumps;i++)
weidendo0a1951d2009-06-15 00:16:36 +0000956 CLG_DEBUG(3, "%d ", clgs.bb->jmp[i].instr);
957 CLG_DEBUG(3, "], last inverted: %s \n",
958 clgs.bb->cjmp_inverted ? "yes":"no");
weidendoa17f2a32006-03-20 10:27:30 +0000959 }
960
weidendo0a1951d2009-06-15 00:16:36 +0000961 return clgs.sbOut;
weidendoa17f2a32006-03-20 10:27:30 +0000962}
963
964/*--------------------------------------------------------------------*/
965/*--- Discarding BB info ---*/
966/*--------------------------------------------------------------------*/
967
968// Called when a translation is removed from the translation cache for
969// any reason at all: to free up space, because the guest code was
970// unmapped or modified, or for any arbitrary reason.
971static
sewardj0b9d74a2006-12-24 02:24:11 +0000972void clg_discard_superblock_info ( Addr64 orig_addr64, VexGuestExtents vge )
weidendoa17f2a32006-03-20 10:27:30 +0000973{
974 Addr orig_addr = (Addr)orig_addr64;
975
976 tl_assert(vge.n_used > 0);
977
978 if (0)
sewardj0b9d74a2006-12-24 02:24:11 +0000979 VG_(printf)( "discard_superblock_info: %p, %p, %llu\n",
weidendoa17f2a32006-03-20 10:27:30 +0000980 (void*)(Addr)orig_addr,
981 (void*)(Addr)vge.base[0], (ULong)vge.len[0]);
982
983 // Get BB info, remove from table, free BB info. Simple! Note that we
984 // use orig_addr, not the first instruction address in vge.
985 CLG_(delete_bb)(orig_addr);
986}
987
988
989/*------------------------------------------------------------*/
990/*--- CLG_(fini)() and related function ---*/
991/*------------------------------------------------------------*/
992
993
994
995static void zero_thread_cost(thread_info* t)
996{
997 Int i;
998
999 for(i = 0; i < CLG_(current_call_stack).sp; i++) {
1000 if (!CLG_(current_call_stack).entry[i].jcc) continue;
1001
1002 /* reset call counters to current for active calls */
1003 CLG_(copy_cost)( CLG_(sets).full,
1004 CLG_(current_call_stack).entry[i].enter_cost,
1005 CLG_(current_state).cost );
weidendoceb06de2009-08-11 20:53:57 +00001006 CLG_(current_call_stack).entry[i].jcc->call_counter = 0;
weidendoa17f2a32006-03-20 10:27:30 +00001007 }
1008
1009 CLG_(forall_bbccs)(CLG_(zero_bbcc));
1010
1011 /* set counter for last dump */
1012 CLG_(copy_cost)( CLG_(sets).full,
1013 t->lastdump_cost, CLG_(current_state).cost );
1014}
1015
1016void CLG_(zero_all_cost)(Bool only_current_thread)
1017{
1018 if (VG_(clo_verbosity) > 1)
sewardj0f33adf2009-07-15 14:51:03 +00001019 VG_(message)(Vg_DebugMsg, " Zeroing costs...\n");
weidendoa17f2a32006-03-20 10:27:30 +00001020
1021 if (only_current_thread)
1022 zero_thread_cost(CLG_(get_current_thread)());
1023 else
1024 CLG_(forall_threads)(zero_thread_cost);
1025
1026 if (VG_(clo_verbosity) > 1)
sewardj0f33adf2009-07-15 14:51:03 +00001027 VG_(message)(Vg_DebugMsg, " ...done\n");
weidendoa17f2a32006-03-20 10:27:30 +00001028}
1029
1030static
1031void unwind_thread(thread_info* t)
1032{
1033 /* unwind signal handlers */
1034 while(CLG_(current_state).sig !=0)
1035 CLG_(post_signal)(CLG_(current_tid),CLG_(current_state).sig);
1036
1037 /* unwind regular call stack */
1038 while(CLG_(current_call_stack).sp>0)
1039 CLG_(pop_call_stack)();
weidendof3e0b492006-09-10 22:34:20 +00001040
1041 /* reset context and function stack for context generation */
1042 CLG_(init_exec_state)( &CLG_(current_state) );
1043 CLG_(current_fn_stack).top = CLG_(current_fn_stack).bottom;
weidendoa17f2a32006-03-20 10:27:30 +00001044}
1045
weidendoe8914872009-08-11 20:53:59 +00001046static
1047void zero_state_cost(thread_info* t)
1048{
1049 CLG_(zero_cost)( CLG_(sets).full, CLG_(current_state).cost );
1050}
1051
weidendoa17f2a32006-03-20 10:27:30 +00001052/* Ups, this can go wrong... */
1053extern void VG_(discard_translations) ( Addr64 start, ULong range );
1054
1055void CLG_(set_instrument_state)(Char* reason, Bool state)
1056{
1057 if (CLG_(instrument_state) == state) {
1058 CLG_DEBUG(2, "%s: instrumentation already %s\n",
1059 reason, state ? "ON" : "OFF");
1060 return;
1061 }
1062 CLG_(instrument_state) = state;
1063 CLG_DEBUG(2, "%s: Switching instrumentation %s ...\n",
1064 reason, state ? "ON" : "OFF");
1065
1066 VG_(discard_translations)( (Addr64)0x1000, (ULong) ~0xfffl);
1067
1068 /* reset internal state: call stacks, simulator */
1069 CLG_(forall_threads)(unwind_thread);
weidendoe8914872009-08-11 20:53:59 +00001070 CLG_(forall_threads)(zero_state_cost);
weidendoa17f2a32006-03-20 10:27:30 +00001071 (*CLG_(cachesim).clear)();
weidendoa17f2a32006-03-20 10:27:30 +00001072
weidendoa17f2a32006-03-20 10:27:30 +00001073 if (VG_(clo_verbosity) > 1)
sewardj0f33adf2009-07-15 14:51:03 +00001074 VG_(message)(Vg_DebugMsg, "%s: instrumentation switched %s\n",
weidendoa17f2a32006-03-20 10:27:30 +00001075 reason, state ? "ON" : "OFF");
1076}
1077
1078
1079static
1080Bool CLG_(handle_client_request)(ThreadId tid, UWord *args, UWord *ret)
1081{
1082 if (!VG_IS_TOOL_USERREQ('C','T',args[0]))
1083 return False;
1084
1085 switch(args[0]) {
1086 case VG_USERREQ__DUMP_STATS:
1087 CLG_(dump_profile)("Client Request", True);
1088 *ret = 0; /* meaningless */
1089 break;
1090
1091 case VG_USERREQ__DUMP_STATS_AT:
1092 {
1093 Char buf[512];
njn8a7b41b2007-09-23 00:51:24 +00001094 VG_(sprintf)(buf,"Client Request: %s", (Char*)args[1]);
weidendoa17f2a32006-03-20 10:27:30 +00001095 CLG_(dump_profile)(buf, True);
1096 *ret = 0; /* meaningless */
1097 }
1098 break;
1099
1100 case VG_USERREQ__ZERO_STATS:
1101 CLG_(zero_all_cost)(True);
1102 *ret = 0; /* meaningless */
1103 break;
1104
1105 case VG_USERREQ__TOGGLE_COLLECT:
1106 CLG_(current_state).collect = !CLG_(current_state).collect;
1107 CLG_DEBUG(2, "Client Request: toggled collection state to %s\n",
1108 CLG_(current_state).collect ? "ON" : "OFF");
1109 *ret = 0; /* meaningless */
1110 break;
1111
1112 case VG_USERREQ__START_INSTRUMENTATION:
1113 CLG_(set_instrument_state)("Client Request", True);
1114 *ret = 0; /* meaningless */
1115 break;
1116
1117 case VG_USERREQ__STOP_INSTRUMENTATION:
1118 CLG_(set_instrument_state)("Client Request", False);
1119 *ret = 0; /* meaningless */
1120 break;
1121
1122 default:
1123 return False;
1124 }
1125
1126 return True;
1127}
1128
1129
1130/* Syscall Timing */
1131
1132/* struct timeval syscalltime[VG_N_THREADS]; */
1133#if CLG_MICROSYSTIME
1134#include <sys/time.h>
1135#include <sys/syscall.h>
1136extern Int VG_(do_syscall) ( UInt, ... );
1137
1138ULong syscalltime[VG_N_THREADS];
1139#else
1140UInt syscalltime[VG_N_THREADS];
1141#endif
1142
1143static
sewardj1c0ce7a2009-07-01 08:10:49 +00001144void CLG_(pre_syscalltime)(ThreadId tid, UInt syscallno,
1145 UWord* args, UInt nArgs)
weidendoa17f2a32006-03-20 10:27:30 +00001146{
1147 if (CLG_(clo).collect_systime) {
1148#if CLG_MICROSYSTIME
1149 struct vki_timeval tv_now;
1150 VG_(do_syscall)(__NR_gettimeofday, (UInt)&tv_now, (UInt)NULL);
1151 syscalltime[tid] = tv_now.tv_sec * 1000000ULL + tv_now.tv_usec;
1152#else
1153 syscalltime[tid] = VG_(read_millisecond_timer)();
1154#endif
1155 }
1156}
1157
1158static
sewardj1c0ce7a2009-07-01 08:10:49 +00001159void CLG_(post_syscalltime)(ThreadId tid, UInt syscallno,
1160 UWord* args, UInt nArgs, SysRes res)
weidendoa17f2a32006-03-20 10:27:30 +00001161{
weidendoae0bb6f2007-02-16 13:12:43 +00001162 if (CLG_(clo).collect_systime &&
1163 CLG_(current_state).bbcc) {
weidendoa17f2a32006-03-20 10:27:30 +00001164 Int o = CLG_(sets).off_full_systime;
1165#if CLG_MICROSYSTIME
1166 struct vki_timeval tv_now;
1167 ULong diff;
1168
1169 VG_(do_syscall)(__NR_gettimeofday, (UInt)&tv_now, (UInt)NULL);
1170 diff = (tv_now.tv_sec * 1000000ULL + tv_now.tv_usec) - syscalltime[tid];
1171#else
1172 UInt diff = VG_(read_millisecond_timer)() - syscalltime[tid];
1173#endif
1174
1175 CLG_DEBUG(0," Time (Off %d) for Syscall %d: %ull\n", o, syscallno, diff);
1176
1177 if (o<0) return;
1178
1179 CLG_(current_state).cost[o] ++;
1180 CLG_(current_state).cost[o+1] += diff;
1181 if (!CLG_(current_state).bbcc->skipped)
1182 CLG_(init_cost_lz)(CLG_(sets).full,
1183 &(CLG_(current_state).bbcc->skipped));
1184 CLG_(current_state).bbcc->skipped[o] ++;
1185 CLG_(current_state).bbcc->skipped[o+1] += diff;
1186 }
1187}
1188
1189static
1190void finish(void)
1191{
1192 char buf[RESULTS_BUF_LEN];
1193
1194 CLG_DEBUG(0, "finish()\n");
1195
1196 (*CLG_(cachesim).finish)();
1197
1198 /* pop all remaining items from CallStack for correct sum
1199 */
1200 CLG_(forall_threads)(unwind_thread);
sewardje45a7992006-10-17 02:24:18 +00001201
weidendoa17f2a32006-03-20 10:27:30 +00001202 CLG_(dump_profile)(0, False);
sewardje45a7992006-10-17 02:24:18 +00001203
weidendoa17f2a32006-03-20 10:27:30 +00001204 CLG_(finish_command)();
sewardje45a7992006-10-17 02:24:18 +00001205
weidendoa17f2a32006-03-20 10:27:30 +00001206 if (VG_(clo_verbosity) == 0) return;
1207
1208 /* Hash table stats */
sewardj2d9e8742009-08-07 15:46:56 +00001209 if (VG_(clo_stats)) {
weidendoa17f2a32006-03-20 10:27:30 +00001210 int BB_lookups =
1211 CLG_(stat).full_debug_BBs +
1212 CLG_(stat).fn_name_debug_BBs +
1213 CLG_(stat).file_line_debug_BBs +
1214 CLG_(stat).no_debug_BBs;
1215
sewardj0f33adf2009-07-15 14:51:03 +00001216 VG_(message)(Vg_DebugMsg, "\n");
1217 VG_(message)(Vg_DebugMsg, "Distinct objects: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001218 CLG_(stat).distinct_objs);
sewardj0f33adf2009-07-15 14:51:03 +00001219 VG_(message)(Vg_DebugMsg, "Distinct files: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001220 CLG_(stat).distinct_files);
sewardj0f33adf2009-07-15 14:51:03 +00001221 VG_(message)(Vg_DebugMsg, "Distinct fns: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001222 CLG_(stat).distinct_fns);
sewardj0f33adf2009-07-15 14:51:03 +00001223 VG_(message)(Vg_DebugMsg, "Distinct contexts:%d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001224 CLG_(stat).distinct_contexts);
sewardj0f33adf2009-07-15 14:51:03 +00001225 VG_(message)(Vg_DebugMsg, "Distinct BBs: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001226 CLG_(stat).distinct_bbs);
sewardj0f33adf2009-07-15 14:51:03 +00001227 VG_(message)(Vg_DebugMsg, "Cost entries: %d (Chunks %d)\n",
weidendoa17f2a32006-03-20 10:27:30 +00001228 CLG_(costarray_entries), CLG_(costarray_chunks));
sewardj0f33adf2009-07-15 14:51:03 +00001229 VG_(message)(Vg_DebugMsg, "Distinct BBCCs: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001230 CLG_(stat).distinct_bbccs);
sewardj0f33adf2009-07-15 14:51:03 +00001231 VG_(message)(Vg_DebugMsg, "Distinct JCCs: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001232 CLG_(stat).distinct_jccs);
sewardj0f33adf2009-07-15 14:51:03 +00001233 VG_(message)(Vg_DebugMsg, "Distinct skips: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001234 CLG_(stat).distinct_skips);
sewardj0f33adf2009-07-15 14:51:03 +00001235 VG_(message)(Vg_DebugMsg, "BB lookups: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001236 BB_lookups);
1237 if (BB_lookups>0) {
sewardj0f33adf2009-07-15 14:51:03 +00001238 VG_(message)(Vg_DebugMsg, "With full debug info:%3d%% (%d)\n",
weidendoa17f2a32006-03-20 10:27:30 +00001239 CLG_(stat).full_debug_BBs * 100 / BB_lookups,
1240 CLG_(stat).full_debug_BBs);
sewardj0f33adf2009-07-15 14:51:03 +00001241 VG_(message)(Vg_DebugMsg, "With file/line debug info:%3d%% (%d)\n",
weidendoa17f2a32006-03-20 10:27:30 +00001242 CLG_(stat).file_line_debug_BBs * 100 / BB_lookups,
1243 CLG_(stat).file_line_debug_BBs);
sewardj0f33adf2009-07-15 14:51:03 +00001244 VG_(message)(Vg_DebugMsg, "With fn name debug info:%3d%% (%d)\n",
weidendoa17f2a32006-03-20 10:27:30 +00001245 CLG_(stat).fn_name_debug_BBs * 100 / BB_lookups,
1246 CLG_(stat).fn_name_debug_BBs);
sewardj0f33adf2009-07-15 14:51:03 +00001247 VG_(message)(Vg_DebugMsg, "With no debug info:%3d%% (%d)\n",
weidendoa17f2a32006-03-20 10:27:30 +00001248 CLG_(stat).no_debug_BBs * 100 / BB_lookups,
1249 CLG_(stat).no_debug_BBs);
1250 }
sewardj0f33adf2009-07-15 14:51:03 +00001251 VG_(message)(Vg_DebugMsg, "BBCC Clones: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001252 CLG_(stat).bbcc_clones);
sewardj0f33adf2009-07-15 14:51:03 +00001253 VG_(message)(Vg_DebugMsg, "BBs Retranslated: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001254 CLG_(stat).bb_retranslations);
sewardj0f33adf2009-07-15 14:51:03 +00001255 VG_(message)(Vg_DebugMsg, "Distinct instrs: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001256 CLG_(stat).distinct_instrs);
1257 VG_(message)(Vg_DebugMsg, "");
1258
sewardj0f33adf2009-07-15 14:51:03 +00001259 VG_(message)(Vg_DebugMsg, "LRU Contxt Misses: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001260 CLG_(stat).cxt_lru_misses);
sewardj0f33adf2009-07-15 14:51:03 +00001261 VG_(message)(Vg_DebugMsg, "LRU BBCC Misses: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001262 CLG_(stat).bbcc_lru_misses);
sewardj0f33adf2009-07-15 14:51:03 +00001263 VG_(message)(Vg_DebugMsg, "LRU JCC Misses: %d\n",
weidendoa17f2a32006-03-20 10:27:30 +00001264 CLG_(stat).jcc_lru_misses);
sewardj0f33adf2009-07-15 14:51:03 +00001265 VG_(message)(Vg_DebugMsg, "BBs Executed: %llu\n",
weidendoa17f2a32006-03-20 10:27:30 +00001266 CLG_(stat).bb_executions);
sewardj0f33adf2009-07-15 14:51:03 +00001267 VG_(message)(Vg_DebugMsg, "Calls: %llu\n",
weidendoa17f2a32006-03-20 10:27:30 +00001268 CLG_(stat).call_counter);
sewardj0f33adf2009-07-15 14:51:03 +00001269 VG_(message)(Vg_DebugMsg, "CondJMP followed: %llu\n",
weidendoa17f2a32006-03-20 10:27:30 +00001270 CLG_(stat).jcnd_counter);
sewardj0f33adf2009-07-15 14:51:03 +00001271 VG_(message)(Vg_DebugMsg, "Boring JMPs: %llu\n",
weidendoa17f2a32006-03-20 10:27:30 +00001272 CLG_(stat).jump_counter);
sewardj0f33adf2009-07-15 14:51:03 +00001273 VG_(message)(Vg_DebugMsg, "Recursive calls: %llu\n",
weidendoa17f2a32006-03-20 10:27:30 +00001274 CLG_(stat).rec_call_counter);
sewardj0f33adf2009-07-15 14:51:03 +00001275 VG_(message)(Vg_DebugMsg, "Returns: %llu\n",
weidendoa17f2a32006-03-20 10:27:30 +00001276 CLG_(stat).ret_counter);
1277
1278 VG_(message)(Vg_DebugMsg, "");
1279 }
1280
1281 CLG_(sprint_eventmapping)(buf, CLG_(dumpmap));
sewardj0f33adf2009-07-15 14:51:03 +00001282 VG_(message)(Vg_UserMsg, "Events : %s\n", buf);
weidendoa17f2a32006-03-20 10:27:30 +00001283 CLG_(sprint_mappingcost)(buf, CLG_(dumpmap), CLG_(total_cost));
sewardj0f33adf2009-07-15 14:51:03 +00001284 VG_(message)(Vg_UserMsg, "Collected : %s\n", buf);
1285 VG_(message)(Vg_UserMsg, "\n");
weidendoa17f2a32006-03-20 10:27:30 +00001286
1287 // if (CLG_(clo).simulate_cache)
1288 (*CLG_(cachesim).printstat)();
1289}
1290
1291
1292void CLG_(fini)(Int exitcode)
1293{
1294 finish();
1295}
1296
1297
1298/*--------------------------------------------------------------------*/
1299/*--- Setup ---*/
1300/*--------------------------------------------------------------------*/
1301
njn3e32c872006-12-24 07:51:17 +00001302static void clg_start_client_code_callback ( ThreadId tid, ULong blocks_done )
sewardj97561812006-12-23 01:21:12 +00001303{
weidendo134657c2006-12-23 23:11:20 +00001304 static ULong last_blocks_done = 0;
1305
sewardj97561812006-12-23 01:21:12 +00001306 if (0)
njn3e32c872006-12-24 07:51:17 +00001307 VG_(printf)("%d R %llu\n", (Int)tid, blocks_done);
weidendo134657c2006-12-23 23:11:20 +00001308
1309 /* throttle calls to CLG_(run_thread) by number of BBs executed */
1310 if (blocks_done - last_blocks_done < 5000) return;
1311 last_blocks_done = blocks_done;
1312
1313 CLG_(run_thread)( tid );
sewardj97561812006-12-23 01:21:12 +00001314}
1315
weidendoa17f2a32006-03-20 10:27:30 +00001316static
1317void CLG_(post_clo_init)(void)
1318{
weidendoa17f2a32006-03-20 10:27:30 +00001319 VG_(clo_vex_control).iropt_unroll_thresh = 0;
1320 VG_(clo_vex_control).guest_chase_thresh = 0;
1321
1322 CLG_DEBUG(1, " dump threads: %s\n", CLG_(clo).separate_threads ? "Yes":"No");
1323 CLG_DEBUG(1, " call sep. : %d\n", CLG_(clo).separate_callers);
1324 CLG_DEBUG(1, " rec. sep. : %d\n", CLG_(clo).separate_recursions);
1325
1326 if (!CLG_(clo).dump_line && !CLG_(clo).dump_instr && !CLG_(clo).dump_bb) {
sewardj0f33adf2009-07-15 14:51:03 +00001327 VG_(message)(Vg_UserMsg, "Using source line as position.\n");
weidendoa17f2a32006-03-20 10:27:30 +00001328 CLG_(clo).dump_line = True;
1329 }
1330
weidendo4ce5e792006-09-20 21:29:39 +00001331 CLG_(init_dumps)();
1332 CLG_(init_command)();
weidendoa17f2a32006-03-20 10:27:30 +00001333
1334 (*CLG_(cachesim).post_clo_init)();
1335
1336 CLG_(init_eventsets)(0);
1337 CLG_(init_statistics)(& CLG_(stat));
1338 CLG_(init_cost_lz)( CLG_(sets).full, &CLG_(total_cost) );
1339
1340 /* initialize hash tables */
1341 CLG_(init_obj_table)();
1342 CLG_(init_cxt_table)();
1343 CLG_(init_bb_hash)();
1344
1345 CLG_(init_threads)();
1346 CLG_(run_thread)(1);
1347
1348 CLG_(instrument_state) = CLG_(clo).instrument_atstart;
1349
weidendoca472c52006-03-31 19:34:51 +00001350 if (VG_(clo_verbosity > 0)) {
weidendoca472c52006-03-31 19:34:51 +00001351 VG_(message)(Vg_UserMsg,
sewardj0f33adf2009-07-15 14:51:03 +00001352 "For interactive control, run 'callgrind_control -h'.\n");
weidendoca472c52006-03-31 19:34:51 +00001353 }
weidendoa17f2a32006-03-20 10:27:30 +00001354}
1355
1356static
1357void CLG_(pre_clo_init)(void)
1358{
1359 VG_(details_name) ("Callgrind");
weidendoca472c52006-03-31 19:34:51 +00001360 VG_(details_version) (NULL);
weidendoa17f2a32006-03-20 10:27:30 +00001361 VG_(details_description) ("a call-graph generating cache profiler");
njn9f207462009-03-10 22:02:09 +00001362 VG_(details_copyright_author)("Copyright (C) 2002-2009, and GNU GPL'd, "
weidendoca472c52006-03-31 19:34:51 +00001363 "by Josef Weidendorfer et al.");
weidendodb70ed72006-05-27 15:39:45 +00001364 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardje45a7992006-10-17 02:24:18 +00001365 VG_(details_avg_translation_sizeB) ( 500 );
weidendoa17f2a32006-03-20 10:27:30 +00001366
1367 VG_(basic_tool_funcs) (CLG_(post_clo_init),
1368 CLG_(instrument),
1369 CLG_(fini));
1370
sewardj0b9d74a2006-12-24 02:24:11 +00001371 VG_(needs_superblock_discards)(clg_discard_superblock_info);
weidendoa17f2a32006-03-20 10:27:30 +00001372
1373
1374 VG_(needs_command_line_options)(CLG_(process_cmd_line_option),
1375 CLG_(print_usage),
1376 CLG_(print_debug_usage));
1377
1378 VG_(needs_client_requests)(CLG_(handle_client_request));
1379 VG_(needs_syscall_wrapper)(CLG_(pre_syscalltime),
1380 CLG_(post_syscalltime));
1381
njn3e32c872006-12-24 07:51:17 +00001382 VG_(track_start_client_code) ( & clg_start_client_code_callback );
1383 VG_(track_pre_deliver_signal) ( & CLG_(pre_signal) );
1384 VG_(track_post_deliver_signal)( & CLG_(post_signal) );
weidendoa17f2a32006-03-20 10:27:30 +00001385
1386 CLG_(set_clo_defaults)();
1387}
1388
1389VG_DETERMINE_INTERFACE_VERSION(CLG_(pre_clo_init))
1390
1391/*--------------------------------------------------------------------*/
1392/*--- end main.c ---*/
1393/*--------------------------------------------------------------------*/