static void CLG_(post_syscalltime)(ThreadId tid, UInt syscallno, SysRes res) { if (CLG_(clo).collect_systime) { Int o = CLG_(sets).off_full_systime; #if CLG_MICROSYSTIME struct vki_timeval tv_now; ULong diff; VG_(do_syscall)(__NR_gettimeofday, (UInt)&tv_now, (UInt)NULL); diff = (tv_now.tv_sec * 1000000ULL + tv_now.tv_usec) - syscalltime[tid]; #else UInt diff = VG_(read_millisecond_timer)() - syscalltime[tid]; #endif CLG_DEBUG(0," Time (Off %d) for Syscall %d: %ull\n", o, syscallno, diff); if (o<0) return; CLG_(current_state).cost[o] ++; CLG_(current_state).cost[o+1] += diff; if (!CLG_(current_state).bbcc->skipped) CLG_(init_cost_lz)(CLG_(sets).full, &(CLG_(current_state).bbcc->skipped)); CLG_(current_state).bbcc->skipped[o] ++; CLG_(current_state).bbcc->skipped[o+1] += diff; } }
/* * Zero all costs of a BBCC */ void CLG_(zero_bbcc)(BBCC* bbcc) { Int i; jCC* jcc; CLG_ASSERT(bbcc->cxt != 0); CLG_DEBUG(1, " zero_bbcc: BB %#lx, Cxt %d " "(fn '%s', rec %d)\n", bb_addr(bbcc->bb), bbcc->cxt->base_number + bbcc->rec_index, bbcc->cxt->fn[0]->name, bbcc->rec_index); if ((bbcc->ecounter_sum ==0) && (bbcc->ret_counter ==0)) return; for(i=0;i<bbcc->bb->cost_count;i++) bbcc->cost[i] = 0; for(i=0;i <= bbcc->bb->cjmp_count;i++) { bbcc->jmp[i].ecounter = 0; for(jcc=bbcc->jmp[i].jcc_list; jcc; jcc=jcc->next_from) CLG_(init_cost)( CLG_(sets).full, jcc->cost ); } bbcc->ecounter_sum = 0; bbcc->ret_counter = 0; }
/* Lookup for a BBCC in hash. */ static BBCC* lookup_bbcc(BB* bb, Context* cxt) { BBCC* bbcc = bb->last_bbcc; UInt idx; /* check LRU */ if (bbcc->cxt == cxt) { if (!CLG_(clo).separate_threads) { /* if we don't dump threads separate, tid doesn't have to match */ return bbcc; } if (bbcc->tid == CLG_(current_tid)) return bbcc; } CLG_(stat).bbcc_lru_misses++; idx = bbcc_hash_idx(bb, cxt, current_bbccs.size); bbcc = current_bbccs.table[idx]; while (bbcc && (bb != bbcc->bb || cxt != bbcc->cxt)) { bbcc = bbcc->next; } CLG_DEBUG(2," lookup_bbcc(BB %#lx, Cxt %d, fn '%s'): %p (tid %d)\n", bb_addr(bb), cxt->base_number, cxt->fn[0]->name, bbcc, bbcc ? bbcc->tid : 0); CLG_DEBUGIF(2) if (bbcc) CLG_(print_bbcc)(-2,bbcc); return bbcc; }
void CLG_(print_context)(void) { BBCC* bbcc; CLG_DEBUG(0,"In tid %d [%d] ", CLG_(current_tid), CLG_(current_call_stack).sp); bbcc = CLG_(current_state).bbcc; print_mangled_cxt(CLG_(current_state).cxt, bbcc ? bbcc->rec_index : 0); VG_(printf)("\n"); }
static void CLG_(post_clo_init)(void) { Char *dir = 0, *fname = 0; VG_(clo_vex_control).iropt_unroll_thresh = 0; VG_(clo_vex_control).guest_chase_thresh = 0; CLG_DEBUG(1, " dump threads: %s\n", CLG_(clo).separate_threads ? "Yes":"No"); CLG_DEBUG(1, " call sep. : %d\n", CLG_(clo).separate_callers); CLG_DEBUG(1, " rec. sep. : %d\n", CLG_(clo).separate_recursions); if (!CLG_(clo).dump_line && !CLG_(clo).dump_instr && !CLG_(clo).dump_bb) { VG_(message)(Vg_UserMsg, "Using source line as position."); CLG_(clo).dump_line = True; } CLG_(init_files)(&dir,&fname); CLG_(init_command)(dir,fname); (*CLG_(cachesim).post_clo_init)(); CLG_(init_eventsets)(0); CLG_(init_statistics)(& CLG_(stat)); CLG_(init_cost_lz)( CLG_(sets).full, &CLG_(total_cost) ); /* initialize hash tables */ CLG_(init_obj_table)(); CLG_(init_cxt_table)(); CLG_(init_bb_hash)(); CLG_(init_threads)(); CLG_(run_thread)(1); CLG_(instrument_state) = CLG_(clo).instrument_atstart; if (VG_(clo_verbosity > 0)) { VG_(message)(Vg_UserMsg, "For interactive control, run 'callgrind_control -h'."); } }
void CLG_(set_instrument_state)(Char* reason, Bool state) { if (CLG_(instrument_state) == state) { CLG_DEBUG(2, "%s: instrumentation already %s\n", reason, state ? "ON" : "OFF"); return; } CLG_(instrument_state) = state; CLG_DEBUG(2, "%s: Switching instrumentation %s ...\n", reason, state ? "ON" : "OFF"); VG_(discard_translations)( (Addr64)0x1000, (ULong) ~0xfffl); /* reset internal state: call stacks, simulator */ CLG_(forall_threads)(unwind_thread); (*CLG_(cachesim).clear)(); if (0) CLG_(forall_threads)(zero_thread_cost); if (VG_(clo_verbosity) > 1) VG_(message)(Vg_DebugMsg, "%s: instrumentation switched %s", reason, state ? "ON" : "OFF"); }
/* double size of hash table 1 (addr->BBCC) */ static void resize_bbcc_hash(void) { Int i, new_size, conflicts1 = 0, conflicts2 = 0; BBCC** new_table; UInt new_idx; BBCC *curr_BBCC, *next_BBCC; new_size = 2*current_bbccs.size+3; new_table = (BBCC**) CLG_MALLOC("cl.bbcc.rbh.1", new_size * sizeof(BBCC*)); if (!new_table) return; for (i = 0; i < new_size; i++) new_table[i] = NULL; for (i = 0; i < current_bbccs.size; i++) { if (current_bbccs.table[i] == NULL) continue; curr_BBCC = current_bbccs.table[i]; while (NULL != curr_BBCC) { next_BBCC = curr_BBCC->next; new_idx = bbcc_hash_idx(curr_BBCC->bb, curr_BBCC->cxt, new_size); curr_BBCC->next = new_table[new_idx]; new_table[new_idx] = curr_BBCC; if (curr_BBCC->next) { conflicts1++; if (curr_BBCC->next->next) conflicts2++; } curr_BBCC = next_BBCC; } } VG_(free)(current_bbccs.table); CLG_DEBUG(0,"Resize BBCC Hash: %d => %d (entries %d, conflicts %d/%d)\n", current_bbccs.size, new_size, current_bbccs.entries, conflicts1, conflicts2); current_bbccs.size = new_size; current_bbccs.table = new_table; CLG_(stat).bbcc_hash_resizes++; }
static Bool CLG_(handle_client_request)(ThreadId tid, UWord *args, UWord *ret) { if (!VG_IS_TOOL_USERREQ('C','T',args[0])) return False; switch(args[0]) { case VG_USERREQ__DUMP_STATS: CLG_(dump_profile)("Client Request", True); *ret = 0; /* meaningless */ break; case VG_USERREQ__DUMP_STATS_AT: { Char buf[512]; VG_(sprintf)(buf,"Client Request: %s", args[1]); CLG_(dump_profile)(buf, True); *ret = 0; /* meaningless */ } break; case VG_USERREQ__ZERO_STATS: CLG_(zero_all_cost)(True); *ret = 0; /* meaningless */ break; case VG_USERREQ__TOGGLE_COLLECT: CLG_(current_state).collect = !CLG_(current_state).collect; CLG_DEBUG(2, "Client Request: toggled collection state to %s\n", CLG_(current_state).collect ? "ON" : "OFF"); *ret = 0; /* meaningless */ break; case VG_USERREQ__START_INSTRUMENTATION: CLG_(set_instrument_state)("Client Request", True); *ret = 0; /* meaningless */ break; case VG_USERREQ__STOP_INSTRUMENTATION: CLG_(set_instrument_state)("Client Request", False); *ret = 0; /* meaningless */ break; default: return False; } return True; }
/* double size of bb table */ static void resize_bb_table(void) { Int i, new_size, conflicts1 = 0, conflicts2 = 0; BB **new_table, *curr, *next; UInt new_idx; new_size = 2* bbs.size +3; new_table = (BB**) CLG_MALLOC(new_size * sizeof(BB*)); if (!new_table) return; for (i = 0; i < new_size; i++) new_table[i] = NULL; for (i = 0; i < bbs.size; i++) { if (bbs.table[i] == NULL) continue; curr = bbs.table[i]; while (NULL != curr) { next = curr->next; new_idx = bb_hash_idx(curr->obj, curr->offset, new_size); curr->next = new_table[new_idx]; new_table[new_idx] = curr; if (curr->next) { conflicts1++; if (curr->next->next) conflicts2++; } curr = next; } } VG_(free)(bbs.table); CLG_DEBUG(0, "Resize BB Hash: %d => %d (entries %d, conflicts %d/%d)\n", bbs.size, new_size, bbs.entries, conflicts1, conflicts2); bbs.size = new_size; bbs.table = new_table; CLG_(stat).bb_hash_resizes++; }
static void finish(void) { char buf[RESULTS_BUF_LEN]; CLG_DEBUG(0, "finish()\n"); (*CLG_(cachesim).finish)(); /* pop all remaining items from CallStack for correct sum */ CLG_(forall_threads)(unwind_thread); CLG_(dump_profile)(0, False); CLG_(finish_command)(); if (VG_(clo_verbosity) == 0) return; /* Hash table stats */ if (VG_(clo_verbosity) > 1) { int BB_lookups = CLG_(stat).full_debug_BBs + CLG_(stat).fn_name_debug_BBs + CLG_(stat).file_line_debug_BBs + CLG_(stat).no_debug_BBs; VG_(message)(Vg_DebugMsg, ""); VG_(message)(Vg_DebugMsg, "Distinct objects: %d", CLG_(stat).distinct_objs); VG_(message)(Vg_DebugMsg, "Distinct files: %d", CLG_(stat).distinct_files); VG_(message)(Vg_DebugMsg, "Distinct fns: %d", CLG_(stat).distinct_fns); VG_(message)(Vg_DebugMsg, "Distinct contexts:%d", CLG_(stat).distinct_contexts); VG_(message)(Vg_DebugMsg, "Distinct BBs: %d", CLG_(stat).distinct_bbs); VG_(message)(Vg_DebugMsg, "Cost entries: %d (Chunks %d)", CLG_(costarray_entries), CLG_(costarray_chunks)); VG_(message)(Vg_DebugMsg, "Distinct BBCCs: %d", CLG_(stat).distinct_bbccs); VG_(message)(Vg_DebugMsg, "Distinct JCCs: %d", CLG_(stat).distinct_jccs); VG_(message)(Vg_DebugMsg, "Distinct skips: %d", CLG_(stat).distinct_skips); VG_(message)(Vg_DebugMsg, "BB lookups: %d", BB_lookups); if (BB_lookups>0) { VG_(message)(Vg_DebugMsg, "With full debug info:%3d%% (%d)", CLG_(stat).full_debug_BBs * 100 / BB_lookups, CLG_(stat).full_debug_BBs); VG_(message)(Vg_DebugMsg, "With file/line debug info:%3d%% (%d)", CLG_(stat).file_line_debug_BBs * 100 / BB_lookups, CLG_(stat).file_line_debug_BBs); VG_(message)(Vg_DebugMsg, "With fn name debug info:%3d%% (%d)", CLG_(stat).fn_name_debug_BBs * 100 / BB_lookups, CLG_(stat).fn_name_debug_BBs); VG_(message)(Vg_DebugMsg, "With no debug info:%3d%% (%d)", CLG_(stat).no_debug_BBs * 100 / BB_lookups, CLG_(stat).no_debug_BBs); } VG_(message)(Vg_DebugMsg, "BBCC Clones: %d", CLG_(stat).bbcc_clones); VG_(message)(Vg_DebugMsg, "BBs Retranslated: %d", CLG_(stat).bb_retranslations); VG_(message)(Vg_DebugMsg, "Distinct instrs: %d", CLG_(stat).distinct_instrs); VG_(message)(Vg_DebugMsg, ""); VG_(message)(Vg_DebugMsg, "LRU Contxt Misses: %d", CLG_(stat).cxt_lru_misses); VG_(message)(Vg_DebugMsg, "LRU BBCC Misses: %d", CLG_(stat).bbcc_lru_misses); VG_(message)(Vg_DebugMsg, "LRU JCC Misses: %d", CLG_(stat).jcc_lru_misses); VG_(message)(Vg_DebugMsg, "BBs Executed: %llu", CLG_(stat).bb_executions); VG_(message)(Vg_DebugMsg, "Calls: %llu", CLG_(stat).call_counter); VG_(message)(Vg_DebugMsg, "CondJMP followed: %llu", CLG_(stat).jcnd_counter); VG_(message)(Vg_DebugMsg, "Boring JMPs: %llu", CLG_(stat).jump_counter); VG_(message)(Vg_DebugMsg, "Recursive calls: %llu", CLG_(stat).rec_call_counter); VG_(message)(Vg_DebugMsg, "Returns: %llu", CLG_(stat).ret_counter); VG_(message)(Vg_DebugMsg, ""); } CLG_(sprint_eventmapping)(buf, CLG_(dumpmap)); VG_(message)(Vg_UserMsg, "Events : %s", buf); CLG_(sprint_mappingcost)(buf, CLG_(dumpmap), CLG_(total_cost)); VG_(message)(Vg_UserMsg, "Collected : %s", buf); VG_(message)(Vg_UserMsg, ""); // if (CLG_(clo).simulate_cache) (*CLG_(cachesim).printstat)(); }
static IRBB* CLG_(instrument)( VgCallbackClosure* closure, IRBB* bbIn, VexGuestLayout* layout, VexGuestExtents* vge, IRType gWordTy, IRType hWordTy ) { Int i; IRBB* bbOut; IRStmt* st, *stnext; Addr instrAddr, origAddr; UInt instrLen = 0, dataSize; UInt instrCount, costOffset; IRExpr *loadAddrExpr, *storeAddrExpr; BB* bb; IRDirty* di; IRExpr *arg1, **argv; Bool bb_seen_before = False; UInt cJumps = 0, cJumpsCorrected; Bool beforeIBoundary, instrIssued; if (gWordTy != hWordTy) { /* We don't currently support this case. */ VG_(tool_panic)("host/guest word size mismatch"); } // No instrumentation if it is switched off if (! CLG_(instrument_state)) { CLG_DEBUG(5, "instrument(BB %p) [Instrumentation OFF]\n", (Addr)closure->readdr); return bbIn; } CLG_DEBUG(3, "+ instrument(BB %p)\n", (Addr)closure->readdr); /* Set up BB for instrumented IR */ bbOut = emptyIRBB(); bbOut->tyenv = dopyIRTypeEnv(bbIn->tyenv); bbOut->next = dopyIRExpr(bbIn->next); bbOut->jumpkind = bbIn->jumpkind; // Copy verbatim any IR preamble preceding the first IMark i = 0; while (i < bbIn->stmts_used && bbIn->stmts[i]->tag != Ist_IMark) { addStmtToIRBB( bbOut, bbIn->stmts[i] ); i++; } // Get the first statement, and origAddr from it CLG_ASSERT(bbIn->stmts_used > 0); st = bbIn->stmts[i]; CLG_ASSERT(Ist_IMark == st->tag); instrAddr = origAddr = (Addr)st->Ist.IMark.addr; CLG_ASSERT(origAddr == st->Ist.IMark.addr); // XXX: check no overflow /* Get BB (creating if necessary). * JS: The hash table is keyed with orig_addr_noredir -- important! * JW: Why? If it is because of different chasing of the redirection, * this is not needed, as chasing is switched off in callgrind */ bb = CLG_(get_bb)(origAddr, bbIn, &bb_seen_before); //bb = CLG_(get_bb)(orig_addr_noredir, bbIn, &bb_seen_before); /* * Precondition: * - jmps_passed has number of cond.jumps passed in last executed BB * - current_bbcc has a pointer to the BBCC of the last executed BB * Thus, if bbcc_jmpkind is != -1 (JmpNone), * current_bbcc->bb->jmp_addr * gives the address of the jump source. * * The BBCC setup does 2 things: * - trace call: * * Unwind own call stack, i.e sync our ESP with real ESP * This is for ESP manipulation (longjmps, C++ exec handling) and RET * * For CALLs or JMPs crossing objects, record call arg + * push are on own call stack * * - prepare for cache log functions: * Set current_bbcc to BBCC that gets the costs for this BB execution * attached */ // helper call to setup_bbcc, with pointer to basic block info struct as argument arg1 = mkIRExpr_HWord( (HWord)bb ); argv = mkIRExprVec_1(arg1); di = unsafeIRDirty_0_N( 1, "setup_bbcc", VG_(fnptr_to_fnentry)( & CLG_(setup_bbcc) ), argv); addStmtToIRBB( bbOut, IRStmt_Dirty(di) ); instrCount = 0; costOffset = 0; // loop for each host instruction (starting from 'i') do { // We should be at an IMark statement CLG_ASSERT(Ist_IMark == st->tag); // Reset stuff for this original instruction loadAddrExpr = storeAddrExpr = NULL; instrIssued = False; dataSize = 0; // Process all the statements for this original instruction (ie. until // the next IMark statement, or the end of the block) do { i++; stnext = ( i < bbIn->stmts_used ? bbIn->stmts[i] : NULL ); beforeIBoundary = !stnext || (Ist_IMark == stnext->tag); collectStatementInfo(bbIn->tyenv, bbOut, st, &instrAddr, &instrLen, &loadAddrExpr, &storeAddrExpr, &dataSize, hWordTy); // instrument a simulator call before conditional jumps if (st->tag == Ist_Exit) { // Nb: instrLen will be zero if Vex failed to decode it. // Also Client requests can appear to be very large (eg. 18 // bytes on x86) because they are really multiple instructions. CLG_ASSERT( 0 == instrLen || bbIn->jumpkind == Ijk_ClientReq || (instrLen >= VG_MIN_INSTR_SZB && instrLen <= VG_MAX_INSTR_SZB) ); // Add instrumentation before this statement endOfInstr(bbOut, &(bb->instr[instrCount]), bb_seen_before, instrAddr - origAddr, instrLen, dataSize, &costOffset, instrIssued, loadAddrExpr, storeAddrExpr); // prepare for a possible further simcall in same host instr loadAddrExpr = storeAddrExpr = NULL; instrIssued = True; if (!bb_seen_before) { bb->jmp[cJumps].instr = instrCount; bb->jmp[cJumps].skip = False; } /* Update global variable jmps_passed (this is before the jump!) * A correction is needed if VEX inverted the last jump condition */ cJumpsCorrected = cJumps; if ((cJumps+1 == bb->cjmp_count) && bb->cjmp_inverted) cJumpsCorrected++; addConstMemStoreStmt( bbOut, (UWord) &CLG_(current_state).jmps_passed, cJumpsCorrected, hWordTy); cJumps++; } addStmtToIRBB( bbOut, st ); st = stnext; } while (!beforeIBoundary); // Add instrumentation for this original instruction. if (!instrIssued || (loadAddrExpr != 0) || (storeAddrExpr !=0)) endOfInstr(bbOut, &(bb->instr[instrCount]), bb_seen_before, instrAddr - origAddr, instrLen, dataSize, &costOffset, instrIssued, loadAddrExpr, storeAddrExpr); instrCount++; } while (st); /* Always update global variable jmps_passed (at end of BB) * A correction is needed if VEX inverted the last jump condition */ cJumpsCorrected = cJumps; if (bb->cjmp_inverted) cJumpsCorrected--; addConstMemStoreStmt( bbOut, (UWord) &CLG_(current_state).jmps_passed, cJumpsCorrected, hWordTy); /* This stores the instr of the call/ret at BB end */ bb->jmp[cJumps].instr = instrCount-1; CLG_ASSERT(bb->cjmp_count == cJumps); CLG_ASSERT(bb->instr_count == instrCount); instrAddr += instrLen; if (bb_seen_before) { CLG_ASSERT(bb->instr_len == instrAddr - origAddr); CLG_ASSERT(bb->cost_count == costOffset); CLG_ASSERT(bb->jmpkind == bbIn->jumpkind); } else { bb->instr_len = instrAddr - origAddr; bb->cost_count = costOffset; bb->jmpkind = bbIn->jumpkind; } CLG_DEBUG(3, "- instrument(BB %p): byteLen %u, CJumps %u, CostLen %u\n", origAddr, bb->instr_len, bb->cjmp_count, bb->cost_count); if (cJumps>0) { CLG_DEBUG(3, " [ "); for (i=0; i<cJumps; i++) CLG_DEBUG(3, "%d ", bb->jmp[i].instr); CLG_DEBUG(3, "], last inverted: %s \n", bb->cjmp_inverted ? "yes":"no"); } return bbOut; }
/* Instrumentation before a conditional jump or at the end * of each original instruction. * Fills the InstrInfo struct if not seen before */ static void endOfInstr(IRBB* bbOut, InstrInfo* ii, Bool bb_seen_before, UInt instr_offset, UInt instrLen, UInt dataSize, UInt* cost_offset, Bool instrIssued, IRExpr* loadAddrExpr, IRExpr* storeAddrExpr) { IRType wordTy; EventSet* es; // Stay sane ... CLG_ASSERT(sizeof(HWord) == sizeof(void*)); if (sizeof(HWord) == 4) { wordTy = Ity_I32; } else if (sizeof(HWord) == 8) { wordTy = Ity_I64; } else { VG_(tool_panic)("endOfInstr: strange word size"); } if (loadAddrExpr) CLG_ASSERT(wordTy == typeOfIRExpr(bbOut->tyenv, loadAddrExpr)); if (storeAddrExpr) CLG_ASSERT(wordTy == typeOfIRExpr(bbOut->tyenv, storeAddrExpr)); // Large (eg. 28B, 108B, 512B on x86) data-sized instructions will be // done inaccurately, but they're very rare and this avoids errors from // hitting more than two cache lines in the simulation. if (dataSize > MIN_LINE_SIZE) dataSize = MIN_LINE_SIZE; /* returns 0 if simulator needs no instrumentation */ es = insert_simcall(bbOut, ii, dataSize, instrIssued, loadAddrExpr, storeAddrExpr); CLG_DEBUG(5, " Instr +%2d (Size %d, DSize %d): ESet %s (Size %d)\n", instr_offset, instrLen, dataSize, es ? es->name : (Char*)"(no instrumentation)", es ? es->size : 0); if (bb_seen_before) { CLG_DEBUG(5, " before: Instr +%2d (Size %d, DSize %d)\n", ii->instr_offset, ii->instr_size, ii->data_size); CLG_ASSERT(ii->instr_offset == instr_offset); CLG_ASSERT(ii->instr_size == instrLen); CLG_ASSERT(ii->cost_offset == *cost_offset); CLG_ASSERT(ii->eventset == es); /* Only check size if data size >0. * This is needed: e.g. for rep or cmov x86 instructions, the same InstrInfo * is used both for 2 simulator calls: for the pure instruction fetch and * separately for an memory access (which may not happen depending on flags). * If checked always, this triggers an assertion failure on retranslation. */ if (dataSize>0) CLG_ASSERT(ii->data_size == dataSize); } else { ii->instr_offset = instr_offset; ii->instr_size = instrLen; ii->cost_offset = *cost_offset; ii->eventset = es; /* data size only relevant if >0 */ if (dataSize > 0) ii->data_size = dataSize; CLG_(stat).distinct_instrs++; } *cost_offset += es ? es->size : 0; }
void* CLG_(malloc)(HChar* cc, UWord s, char* f) { CLG_DEBUG(3, "Malloc(%lu) in %s.\n", s, f); return VG_(malloc)(cc,s); }
/** * Setup for interactive control of a callgrind run */ static void setup_control(void) { Int fd, size; SysRes res; Char* dir; CLG_ASSERT(thisPID != 0); fd = -1; dir = CLG_(get_out_directory)(); out_file = CLG_(get_out_file)(); /* name of command file */ size = VG_(strlen)(dir) + VG_(strlen)(DEFAULT_COMMANDNAME) +10; command_file = (char*) CLG_MALLOC(size); CLG_ASSERT(command_file != 0); VG_(sprintf)(command_file, "%s/%s.%d", dir, DEFAULT_COMMANDNAME, thisPID); /* This is for compatibility with the "Force Now" Button of current * KCachegrind releases, as it doesn't use ".pid" to distinguish * different callgrind instances from same base directory. */ command_file2 = (char*) CLG_MALLOC(size); CLG_ASSERT(command_file2 != 0); VG_(sprintf)(command_file2, "%s/%s", dir, DEFAULT_COMMANDNAME); size = VG_(strlen)(dir) + VG_(strlen)(DEFAULT_RESULTNAME) +10; result_file = (char*) CLG_MALLOC(size); CLG_ASSERT(result_file != 0); VG_(sprintf)(result_file, "%s/%s.%d", dir, DEFAULT_RESULTNAME, thisPID); /* If we get a command from a command file without .pid, use * a result file without .pid suffix */ result_file2 = (char*) CLG_MALLOC(size); CLG_ASSERT(result_file2 != 0); VG_(sprintf)(result_file2, "%s/%s", dir, DEFAULT_RESULTNAME); info_file = (char*) CLG_MALLOC(VG_(strlen)(DEFAULT_INFONAME) + 10); CLG_ASSERT(info_file != 0); VG_(sprintf)(info_file, "%s.%d", DEFAULT_INFONAME, thisPID); CLG_DEBUG(1, "Setup for interactive control (PID: %d):\n", thisPID); CLG_DEBUG(1, " output file: '%s'\n", out_file); CLG_DEBUG(1, " command file: '%s'\n", command_file); CLG_DEBUG(1, " result file: '%s'\n", result_file); CLG_DEBUG(1, " info file: '%s'\n", info_file); /* create info file to indicate that we are running */ res = VG_(open)(info_file, VKI_O_WRONLY|VKI_O_TRUNC, 0); if (res.isError) { res = VG_(open)(info_file, VKI_O_CREAT|VKI_O_WRONLY, VKI_S_IRUSR|VKI_S_IWUSR); if (res.isError) { VG_(message)(Vg_DebugMsg, "warning: can't write info file '%s'", info_file); info_file = 0; fd = -1; } } if (!res.isError) fd = (Int) res.res; if (fd>=0) { Char buf[512]; Int i; WRITE_STR3(fd, "# This file is generated by Callgrind-" VERSION ".\n" "# It is used to enable controlling the supervision of\n" "# '", VG_(args_the_exename), "'\n" "# by external tools.\n\n"); VG_(sprintf)(buf, "version: " COMMAND_VERSION "\n"); VG_(write)(fd, (void*)buf, VG_(strlen)(buf)); WRITE_STR3(fd, "base: ", dir, "\n"); WRITE_STR3(fd, "dumps: ", out_file, "\n"); WRITE_STR3(fd, "control: ", command_file, "\n"); WRITE_STR3(fd, "result: ", result_file, "\n"); WRITE_STR2(fd, "cmd: ", VG_(args_the_exename)); for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) { HChar* arg = * (HChar**)VG_(indexXA)( VG_(args_for_client), i ); if (!arg) continue; WRITE_STR2(fd, " ", arg); } VG_(write)(fd, "\n", 1); VG_(close)(fd); } }
void* CLG_(malloc)(UWord s, char* f) { CLG_DEBUG(3, "Malloc(%d) in %s.\n", s, f); return VG_(malloc)(s); }