Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions callgrind/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ CALLGRIND_SOURCES_COMMON = \
jumps.c \
main.c \
sim.c \
subprocess.c \
threads.c

# We sneakily include "cg_branchpred.c" and "cg_arch.c" from cachegrind
Expand Down
13 changes: 10 additions & 3 deletions callgrind/clo.c
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,12 @@ Bool CLG_(process_cmd_line_option)(const HChar* arg)

else if VG_BOOL_CLO(arg, "--collect-atstart", CLG_(clo).collect_atstart) {}

else if VG_BOOL_CLO(arg, "--instr-atstart", CLG_(clo).instrument_atstart) {}
else if VG_XACT_CLO(arg, "--instr-atstart=no",
CLG_(clo).instrument_atstart, instr_atstart_no) {}
else if VG_XACT_CLO(arg, "--instr-atstart=yes",
CLG_(clo).instrument_atstart, instr_atstart_yes) {}
else if VG_XACT_CLO(arg, "--instr-atstart=inherit",
CLG_(clo).instrument_atstart, instr_atstart_inherit) {}

else if VG_BOOL_CLO(arg, "--separate-threads", CLG_(clo).separate_threads) {}

Expand Down Expand Up @@ -604,7 +609,9 @@ void CLG_(print_usage)(void)
#endif

"\n data collection options:\n"
" --instr-atstart=no|yes Do instrumentation at callgrind start [yes]\n"
" --instr-atstart=no|yes|inherit Do instrumentation at callgrind start [yes]\n"
" inherit Like 'no', but inherit the instrumentation state across\n"
" a traced exec.\n"
" --collect-atstart=no|yes Collect at process/thread start [yes]\n"
" --toggle-collect=<func> Toggle collection on enter/leave function\n"
" --collect-jumps=no|yes Collect jumps? [no]\n"
Expand Down Expand Up @@ -693,7 +700,7 @@ void CLG_(set_clo_defaults)(void)
CLG_(clo).skip_direct_recursion = False;

/* Instrumentation */
CLG_(clo).instrument_atstart = True;
CLG_(clo).instrument_atstart = instr_atstart_yes;
CLG_(clo).simulate_cache = False;
CLG_(clo).simulate_branch = False;
CLG_(clo).cycle_estimation = False;
Expand Down
18 changes: 18 additions & 0 deletions callgrind/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ Int CLG_(get_dump_counter)(void)
return out_counter;
}

/* Restart part numbering in a fork child: its dumps go to a fresh per-pid file
* whose parts start at 1, like an exec'd child. init_dumps() would reset the
* counter anyway on the pid change, but only at the first dump - too late for
* the part number this process forwards to its own children in the meantime. */
void CLG_(reset_dump_counter)(void)
{
out_counter = 0;
}

/*------------------------------------------------------------*/
/*--- Output file related stuff ---*/
/*------------------------------------------------------------*/
Expand Down Expand Up @@ -1369,6 +1378,11 @@ static VgFile *new_dumpfile(thread_info* ti, const HChar* trigger)
}

VG_(fprintf)(fp, "\npart: %d\n", out_counter);

/* Per-part, not in the once-per-file header, so a child spawned during a
* later part is still recorded. */
CLG_(print_spawned_children)(fp);

if (CLG_(clo).separate_threads) {
const HChar* tname = CLG_(thread_name)(ti);

Expand Down Expand Up @@ -1684,6 +1698,10 @@ static void print_bbccs(const HChar* trigger, Bool only_current_thread)
CLG_(forall_threads_incl_exited)(print_one_empty_section);
}

/* All of these have just been emitted under the part being dumped; a later
* part cannot reference them. */
CLG_(forget_spawned_children)();

free_dump_array();
}

Expand Down
29 changes: 28 additions & 1 deletion callgrind/global.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ typedef enum {
systime_nsec
} Collect_Systime;

/* Whether to instrument from the start.
instr_atstart_no : start with instrumentation off
instr_atstart_yes : start with instrumentation on
instr_atstart_inherit : like "no", but adopt the state advertised by this
PID's pre-exec image, and advertise ours likewise */
typedef enum {
instr_atstart_no,
instr_atstart_yes,
instr_atstart_inherit
} Instr_Atstart;

typedef struct _CommandLineOptions CommandLineOptions;
struct _CommandLineOptions {

Expand Down Expand Up @@ -113,7 +124,7 @@ struct _CommandLineOptions {
Bool collect_bus; /* Collect global bus events */

/* Instrument options */
Bool instrument_atstart; /* Instrument at start? */
Instr_Atstart instrument_atstart; /* Instrument at start? */
Bool simulate_cache; /* Call into cache simulator ? */
Bool simulate_branch; /* Call into branch prediction simulator ? */
Bool cycle_estimation; /* Estimate per-instruction cycles (Ct/Cl) ? */
Expand Down Expand Up @@ -730,6 +741,8 @@ void CLG_(zero_all_cost)(Bool only_current_thread);
* an already-unwound or empty state. */
void CLG_(unwind_thread)(thread_info* t);
Int CLG_(get_dump_counter)(void);
void CLG_(reset_dump_counter)(void);
void CLG_(restamp_syscall_time)(ThreadId tid);
void CLG_(fini)(Int exitcode);

/* from bb.c */
Expand Down Expand Up @@ -825,6 +838,20 @@ void CLG_(run_post_signal_on_call_stack_bottom)(void);
/* from dump.c */
void CLG_(init_dumps)(void);

/* from subprocess.c */
void CLG_(init_subprocess)(void);
/* Fed the result of every syscall, to spot the ones spawning a process. */
void CLG_(syscall_return)(SysRes res);
void CLG_(print_spawned_children)(VgFile* fp);
void CLG_(forget_spawned_children)(void);
/* Advertise the instrumentation state this process is in to a process
* inheriting from it, and adopt what was advertised to this one. */
void CLG_(publish_instr_state)(Bool on);
Bool CLG_(inherited_instr_state)(void);
/* Forward an object added via CALLGRIND_ADD_OBJ_SKIP to child valgrind
* processes, as if it had been passed on the command line. */
void CLG_(publish_obj_skip)(const HChar* obj_name);

/*------------------------------------------------------------*/
/*--- Exported global variables ---*/
/*------------------------------------------------------------*/
Expand Down
44 changes: 39 additions & 5 deletions callgrind/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1481,6 +1481,9 @@ void CLG_(set_instrument_state)(const HChar* reason, Bool state)
reason, state ? "ON" : "OFF");
return;
}
/* advertise before switching: the advertised state must never lag behind
* the state this process is actually in */
CLG_(publish_instr_state)(state);
CLG_(instrument_state) = state;
CLG_DEBUG(2, "%s: Switching instrumentation %s ...\n",
reason, state ? "ON" : "OFF");
Expand Down Expand Up @@ -1714,6 +1717,7 @@ Bool CLG_(handle_client_request)(ThreadId tid, UWord *args, UWord *ret)
case VG_USERREQ__ADD_OBJ_SKIP: {
const HChar* path = (const HChar*)args[1];
CLG_(add_obj_to_skip)(path);
CLG_(publish_obj_skip)(path);
*ret = 0;
break;
}
Expand Down Expand Up @@ -1779,12 +1783,22 @@ void collect_time (struct vki_timespec *systime, struct vki_timespec *syscputime
}
}

/* Stamp the start time of the syscall a thread is entering. Also used to
re-stamp it, when what was stamped no longer applies to the clocks the delta
will be computed against. */
void CLG_(restamp_syscall_time)(ThreadId tid)
{
if (CLG_(clo).collect_systime == systime_no) return;

collect_time(&syscalltime[tid],
CLG_(clo).collect_systime == systime_nsec ? &syscallcputime[tid] : NULL);
}

static
void CLG_(pre_syscalltime)(ThreadId tid, UInt syscallno,
UWord* args, UInt nArgs)
{
collect_time(&syscalltime[tid],
CLG_(clo).collect_systime == systime_nsec ? &syscallcputime[tid] : NULL);
CLG_(restamp_syscall_time)(tid);
}

/* Returns "after - before" in the unit as specified by --collect-systime.
Expand Down Expand Up @@ -1814,6 +1828,11 @@ static
void CLG_(post_syscalltime)(ThreadId tid, UInt syscallno,
UWord* args, UInt nArgs, SysRes res)
{
/* The result of a fork is the only place its child's pid appears. */
CLG_(syscall_return)(res);

if (CLG_(clo).collect_systime == systime_no) return;

if (CLG_(current_state).bbcc) {
Int o;
struct vki_timespec ts_now;
Expand Down Expand Up @@ -2054,6 +2073,9 @@ void finish(void)
void CLG_(fini)(Int exitcode)
{
finish();
/* only runs at process exit, not on exec: the advertised state must
* survive a traced exec for the next image to adopt it */
CLG_(publish_instr_state)(False);
}


Expand Down Expand Up @@ -2088,9 +2110,11 @@ void CLG_(post_clo_init)(void)
"sp-at-mem-access\n");
}

/* Always needed: the wrapper is also how a fork's child pid is picked up. */
VG_(needs_syscall_wrapper)(CLG_(pre_syscalltime),
CLG_(post_syscalltime));

if (CLG_(clo).collect_systime != systime_no) {
VG_(needs_syscall_wrapper)(CLG_(pre_syscalltime),
CLG_(post_syscalltime));
syscalltime = CLG_MALLOC("cl.main.pci.1",
VG_N_THREADS * sizeof syscalltime[0]);
for (UInt i = 0; i < VG_N_THREADS; ++i) {
Expand Down Expand Up @@ -2165,7 +2189,15 @@ void CLG_(post_clo_init)(void)
CLG_(init_threads)();
CLG_(run_thread)(1);

CLG_(instrument_state) = CLG_(clo).instrument_atstart;
switch (CLG_(clo).instrument_atstart) {
case instr_atstart_yes: CLG_(instrument_state) = True; break;
case instr_atstart_no: CLG_(instrument_state) = False; break;
case instr_atstart_inherit:
/* the adopted state is already the advertised one, so nothing to
* publish here: the file this image found is the file it keeps */
CLG_(instrument_state) = CLG_(inherited_instr_state)();
break;
}

if (VG_(clo_verbosity) > 0) {
VG_(message)(Vg_UserMsg,
Expand Down Expand Up @@ -2212,6 +2244,8 @@ void CLG_(pre_clo_init)(void)
VG_(track_post_deliver_signal)( & CLG_(post_signal) );
VG_(track_pre_thread_ll_exit) ( & CLG_(pre_thread_ll_exit) );

CLG_(init_subprocess)();

CLG_(set_clo_defaults)();

}
Expand Down
Loading
Loading