Assorted fixes in exp-bbv to eliminate a few buffers.
Implement a suggestion found in the massif source, namely to add the
equivalent of fprintf to m_libcprint. Good suggestion. Thusly
- VgFile: similar to FILE; buffered output, 8k buffer
- VG_(fopen): similar to fopen, but with arguments as in VG_(open)
- VG_(fprintf) and VG_(vfprintf): like [v]fprintf with VgFile 1at argument
- VG_(fclose)
Change massif, exp-bbv and cachegrind to use this functionality.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@14678
static void fprint_CC_table_and_calc_totals(void)
{
- Int i, fd;
- SysRes sres;
- HChar buf[512];
+ Int i;
+ VgFile *fp;
HChar *currFile = NULL;
const HChar *currFn = NULL;
LineCC* lineCC;
HChar* cachegrind_out_file =
VG_(expand_file_name)("--cachegrind-out-file", clo_cachegrind_out_file);
- sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
- VKI_S_IRUSR|VKI_S_IWUSR);
- if (sr_isError(sres)) {
+ fp = VG_(fopen)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
+ VKI_S_IRUSR|VKI_S_IWUSR);
+ if (fp == NULL) {
// If the file can't be opened for whatever reason (conflict
// between multiple cachegrinded processes?), give up now.
VG_(umsg)("error: can't open cache simulation output file '%s'\n",
VG_(free)(cachegrind_out_file);
return;
} else {
- fd = sr_Res(sres);
VG_(free)(cachegrind_out_file);
}
// "desc:" lines (giving I1/D1/LL cache configuration). The spaces after
// the 2nd colon makes cg_annotate's output look nicer.
- VG_(sprintf)(buf, "desc: I1 cache: %s\n"
+ VG_(fprintf)(fp, "desc: I1 cache: %s\n"
"desc: D1 cache: %s\n"
"desc: LL cache: %s\n",
I1.desc_line, D1.desc_line, LL.desc_line);
- VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
// "cmd:" line
- VG_(strcpy)(buf, "cmd:");
- VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
- VG_(write)(fd, " ", 1);
- VG_(write)(fd, VG_(args_the_exename),
- VG_(strlen)( VG_(args_the_exename) ));
+ VG_(fprintf)(fp, "cmd: %s", 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 );
- VG_(write)(fd, " ", 1);
- VG_(write)(fd, arg, VG_(strlen)( arg ));
+ VG_(fprintf)(fp, " %s", arg);
}
// "events:" line
if (clo_cache_sim && clo_branch_sim) {
- VG_(sprintf)(buf, "\nevents: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw "
+ VG_(fprintf)(fp, "\nevents: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw "
"Bc Bcm Bi Bim\n");
}
else if (clo_cache_sim && !clo_branch_sim) {
- VG_(sprintf)(buf, "\nevents: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw "
+ VG_(fprintf)(fp, "\nevents: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw "
"\n");
}
else if (!clo_cache_sim && clo_branch_sim) {
- VG_(sprintf)(buf, "\nevents: Ir "
- "Bc Bcm Bi Bim\n");
+ VG_(fprintf)(fp, "\nevents: Ir Bc Bcm Bi Bim\n");
}
else {
- VG_(sprintf)(buf, "\nevents: Ir\n");
+ VG_(fprintf)(fp, "\nevents: Ir\n");
}
- VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
-
// Traverse every lineCC
VG_(OSetGen_ResetIter)(CC_table);
while ( (lineCC = VG_(OSetGen_Next)(CC_table)) ) {
// the whole strings would have to be checked.
if ( lineCC->loc.file != currFile ) {
currFile = lineCC->loc.file;
- VG_(sprintf)(buf, "fl=%s\n", currFile);
- VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
+ VG_(fprintf)(fp, "fl=%s\n", currFile);
distinct_files++;
just_hit_a_new_file = True;
}
// in the old file, hence the just_hit_a_new_file test).
if ( just_hit_a_new_file || lineCC->loc.fn != currFn ) {
currFn = lineCC->loc.fn;
- VG_(sprintf)(buf, "fn=%s\n", currFn);
- VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
+ VG_(fprintf)(fp, "fn=%s\n", currFn);
distinct_fns++;
}
// Print the LineCC
if (clo_cache_sim && clo_branch_sim) {
- VG_(sprintf)(buf, "%u %llu %llu %llu"
+ VG_(fprintf)(fp, "%u %llu %llu %llu"
" %llu %llu %llu"
" %llu %llu %llu"
" %llu %llu %llu %llu\n",
lineCC->Bi.b, lineCC->Bi.mp);
}
else if (clo_cache_sim && !clo_branch_sim) {
- VG_(sprintf)(buf, "%u %llu %llu %llu"
+ VG_(fprintf)(fp, "%u %llu %llu %llu"
" %llu %llu %llu"
" %llu %llu %llu\n",
lineCC->loc.line,
lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.mL);
}
else if (!clo_cache_sim && clo_branch_sim) {
- VG_(sprintf)(buf, "%u %llu"
+ VG_(fprintf)(fp, "%u %llu"
" %llu %llu %llu %llu\n",
lineCC->loc.line,
lineCC->Ir.a,
lineCC->Bi.b, lineCC->Bi.mp);
}
else {
- VG_(sprintf)(buf, "%u %llu\n",
+ VG_(fprintf)(fp, "%u %llu\n",
lineCC->loc.line,
lineCC->Ir.a);
}
- VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
-
// Update summary stats
Ir_total.a += lineCC->Ir.a;
Ir_total.m1 += lineCC->Ir.m1;
// Summary stats must come after rest of table, since we calculate them
// during traversal. */
if (clo_cache_sim && clo_branch_sim) {
- VG_(sprintf)(buf, "summary:"
+ VG_(fprintf)(fp, "summary:"
" %llu %llu %llu"
" %llu %llu %llu"
" %llu %llu %llu"
Bi_total.b, Bi_total.mp);
}
else if (clo_cache_sim && !clo_branch_sim) {
- VG_(sprintf)(buf, "summary:"
+ VG_(fprintf)(fp, "summary:"
" %llu %llu %llu"
" %llu %llu %llu"
" %llu %llu %llu\n",
Dw_total.a, Dw_total.m1, Dw_total.mL);
}
else if (!clo_cache_sim && clo_branch_sim) {
- VG_(sprintf)(buf, "summary:"
+ VG_(fprintf)(fp, "summary:"
" %llu"
" %llu %llu %llu %llu\n",
Ir_total.a,
Bi_total.b, Bi_total.mp);
}
else {
- VG_(sprintf)(buf, "summary:"
+ VG_(fprintf)(fp, "summary:"
" %llu\n",
Ir_total.a);
}
- VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
- VG_(close)(fd);
+ VG_(fclose)(fp);
}
static UInt ULong_width(ULong n)
static void cg_fini(Int exitcode)
{
- static HChar buf1[128], buf2[128], buf3[128], buf4[123];
- static HChar fmt[128];
+ static HChar buf1[128], buf2[128], buf3[128], buf4[123]; // FIXME
+ static HChar fmt[128]; // OK; large enough
CacheCC D_total;
BranchCC B_total;
+/* -*- mode: C; c-basic-offset: 3; -*- */
/*--------------------------------------------------------------------*/
/*--- Libc printing. m_libcprint.c ---*/
#include "pub_core_libcfile.h" // VG_(write)(), VG_(write_socket)()
#include "pub_core_libcprint.h"
#include "pub_core_libcproc.h" // VG_(getpid)(), VG_(read_millisecond_timer()
+#include "pub_core_mallocfree.h" // VG_(malloc)
#include "pub_core_options.h"
#include "pub_core_clreq.h" // For RUNNING_ON_VALGRIND
}
+/* --------- fprintf ---------- */
+
+/* This is like [v]fprintf, except it writes to a file handle using
+ VG_(write). */
+
+#define VGFILE_BUFSIZE 8192
+
+struct _VgFile {
+ HChar buf[VGFILE_BUFSIZE];
+ UInt num_chars; // number of characters in buf
+ Int fd; // file descriptor to write to
+};
+
+
+static void add_to__vgfile ( HChar c, void *p )
+{
+ VgFile *fp = p;
+
+ fp->buf[fp->num_chars++] = c;
+
+ if (fp->num_chars == VGFILE_BUFSIZE) {
+ VG_(write)(fp->fd, fp->buf, fp->num_chars);
+ fp->num_chars = 0;
+ }
+}
+
+VgFile *VG_(fopen)(const HChar *name, Int flags, Int mode)
+{
+ SysRes res = VG_(open)(name, flags, mode);
+
+ if (sr_isError(res))
+ return NULL;
+
+ VgFile *fp = VG_(malloc)("fopen", sizeof(VgFile));
+
+ fp->fd = sr_Res(res);
+ fp->num_chars = 0;
+
+ return fp;
+}
+
+
+UInt VG_(vfprintf) ( VgFile *fp, const HChar *format, va_list vargs )
+{
+ return VG_(debugLog_vprintf)(add_to__vgfile, fp, format, vargs);
+}
+
+UInt VG_(fprintf) ( VgFile *fp, const HChar *format, ... )
+{
+ UInt ret;
+ va_list vargs;
+ va_start(vargs,format);
+ ret = VG_(vfprintf)(fp, format, vargs);
+ va_end(vargs);
+ return ret;
+}
+
+void VG_(fclose)( VgFile *fp )
+{
+ // Flush the buffer.
+ if (fp->num_chars)
+ VG_(write)(fp->fd, fp->buf, fp->num_chars);
+
+ VG_(free)(fp);
+}
+
/* ---------------------------------------------------------------------
percentify()
------------------------------------------------------------------ */
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/
-
+/* -*- mode: C; c-basic-offset: 3; -*- */
+
//--------------------------------------------------------------------*/
//--- BBV: a SimPoint basic block vector generator bbv_main.c ---*/
//--------------------------------------------------------------------*/
#include "pub_tool_tooliface.h"
#include "pub_tool_options.h" /* command line options */
-#include "pub_tool_vki.h" /* vki_stat */
+#include "pub_tool_vki.h" /* VKI_O_CREAT */
#include "pub_tool_libcbase.h" /* VG_(strlen) */
-#include "pub_tool_libcfile.h" /* VG_(write) */
#include "pub_tool_libcprint.h" /* VG_(printf) */
#include "pub_tool_libcassert.h" /* VG_(exit) */
-#include "pub_tool_mallocfree.h" /* plain_free */
+#include "pub_tool_mallocfree.h" /* VG_(malloc) */
#include "pub_tool_machine.h" /* VG_(fnptr_to_fnentry) */
#include "pub_tool_debuginfo.h" /* VG_(get_fnname) */
static Bool instr_count_only=False;
static Bool generate_pc_file=False;
- /* write buffer */
-static HChar buf[1024];
-
/* Global values */
static OSet* instr_info_table; /* table that holds the basic block info */
static Int block_num=1; /* global next block number */
ULong global_rep_count;
ULong unique_rep_count;
ULong fldcw_count; /* fldcw count */
- Int bbtrace_fd; /* file descriptor */
+ VgFile *bbtrace_fp; /* file pointer */
};
struct BB_info {
static void dumpPcFile(void)
{
struct BB_info *bb_elem;
- Int pctrace_fd;
- SysRes sres;
+ VgFile *fp;
pc_out_file =
VG_(expand_file_name)("--pc-out-file", clo_pc_out_file);
- sres = VG_(open)(pc_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
- VKI_S_IRUSR|VKI_S_IWUSR|VKI_S_IRGRP|VKI_S_IWGRP);
- if (sr_isError(sres)) {
+ fp = VG_(fopen)(pc_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
+ VKI_S_IRUSR|VKI_S_IWUSR|VKI_S_IRGRP|VKI_S_IWGRP);
+ if (fp == NULL) {
VG_(umsg)("Error: cannot create pc file %s\n", pc_out_file);
VG_(exit)(1);
- } else {
- pctrace_fd = sr_Res(sres);
}
/* Loop through the table, printing the number, address, */
/* and function name for each basic block */
VG_(OSetGen_ResetIter)(instr_info_table);
while ( (bb_elem = VG_(OSetGen_Next)(instr_info_table)) ) {
- VG_(write)(pctrace_fd,"F",1);
- VG_(sprintf)( buf,":%d:%x:%s\n",
- bb_elem->block_num,
- (Int)bb_elem->BB_addr,
- bb_elem->fn_name);
- VG_(write)(pctrace_fd, (void*)buf, VG_(strlen)(buf));
+ VG_(fprintf)( fp, "F:%d:%x:%s\n", bb_elem->block_num,
+ (Int)bb_elem->BB_addr, bb_elem->fn_name);
}
- VG_(close)(pctrace_fd);
+ VG_(fclose)(fp);
}
-static Int open_tracefile(Int thread_num)
+static VgFile *open_tracefile(Int thread_num)
{
- SysRes sres;
- HChar temp_string[2048];
+ VgFile *fp;
+ // Allocate a buffer large enough for the general case "%s.%d" below
+ HChar temp_string[VG_(strlen)(bb_out_file) + 1 + 10 + 1];
/* For thread 1, don't append any thread number */
/* This lets the single-thread case not have any */
/* extra values appended to the file name. */
if (thread_num==1) {
- VG_(strncpy)(temp_string,bb_out_file,2047);
+ VG_(strcpy)(temp_string, bb_out_file);
}
else {
VG_(sprintf)(temp_string,"%s.%d",bb_out_file,thread_num);
}
- sres = VG_(open)(temp_string, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
- VKI_S_IRUSR|VKI_S_IWUSR|VKI_S_IRGRP|VKI_S_IWGRP);
+ fp = VG_(fopen)(temp_string, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
+ VKI_S_IRUSR|VKI_S_IWUSR|VKI_S_IRGRP|VKI_S_IWGRP);
- if (sr_isError(sres)) {
+ if (fp == NULL) {
VG_(umsg)("Error: cannot create bb file %s\n",temp_string);
VG_(exit)(1);
}
- return sr_Res(sres);
+ return fp;
}
static void handle_overflow(void)
if (!instr_count_only) {
- /* If our output fd hasn't been opened, open it */
- if (bbv_thread[current_thread].bbtrace_fd < 0) {
- bbv_thread[current_thread].bbtrace_fd=open_tracefile(current_thread);
+ /* If our output file hasn't been opened, open it */
+ if (bbv_thread[current_thread].bbtrace_fp == NULL) {
+ bbv_thread[current_thread].bbtrace_fp=open_tracefile(current_thread);
}
/* put an entry to the bb.out file */
- VG_(write)(bbv_thread[current_thread].bbtrace_fd,"T",1);
+ VG_(fprintf)(bbv_thread[current_thread].bbtrace_fp, "T");
VG_(OSetGen_ResetIter)(instr_info_table);
while ( (bb_elem = VG_(OSetGen_Next)(instr_info_table)) ) {
if ( bb_elem->inst_counter[current_thread] != 0 ) {
- VG_(sprintf)( buf,":%d:%d ",
- bb_elem->block_num,
- bb_elem->inst_counter[current_thread]);
- VG_(write)(bbv_thread[current_thread].bbtrace_fd,
- (void*)buf, VG_(strlen)(buf));
+ VG_(fprintf)(bbv_thread[current_thread].bbtrace_fp, ":%d:%d ",
+ bb_elem->block_num,
+ bb_elem->inst_counter[current_thread]);
bb_elem->inst_counter[current_thread] = 0;
}
}
- VG_(write)(bbv_thread[current_thread].bbtrace_fd,"\n",1);
+ VG_(fprintf)(bbv_thread[current_thread].bbtrace_fp, "\n");
}
bbv_thread[current_thread].dyn_instr -= interval_size;
temp[i].unique_rep_count=0;
temp[i].rep_count=0;
temp[i].fldcw_count=0;
- temp[i].bbtrace_fd=-1;
+ temp[i].bbtrace_fp=NULL;
}
/* expand the inst_counter on all allocated basic blocks */
VG_(OSetGen_ResetIter)(instr_info_table);
for(i=0;i<allocated_threads;i++) {
if (bbv_thread[i].total_instr!=0) {
-
+ HChar buf[500]; // large enough
VG_(sprintf)(buf,"\n\n"
"# Thread %d\n"
"# Total intervals: %d (Interval Size %d)\n"
VG_(umsg)("%s\n", buf);
/* open the output file if it hasn't already */
- if (bbv_thread[i].bbtrace_fd < 0) {
- bbv_thread[i].bbtrace_fd=open_tracefile(i);
+ if (bbv_thread[i].bbtrace_fp == NULL) {
+ bbv_thread[i].bbtrace_fp=open_tracefile(i);
}
/* Also print to results file */
- VG_(write)(bbv_thread[i].bbtrace_fd,(void*)buf,VG_(strlen)(buf));
- VG_(close)(bbv_thread[i].bbtrace_fd);
+ VG_(fprintf)(bbv_thread[i].bbtrace_fp, "%s", buf);
+ VG_(fclose)(bbv_thread[i].bbtrace_fp);
}
}
}
extern UInt VG_(vprintf_xml) ( const HChar *format, va_list vargs )
PRINTF_CHECK(1, 0);
+typedef struct _VgFile VgFile;
+
+extern VgFile *VG_(fopen) ( const HChar *name, Int flags, Int mode );
+extern void VG_(fclose) ( VgFile *fp );
+extern UInt VG_(fprintf) ( VgFile *fp, const HChar *format, ... )
+ PRINTF_CHECK(2, 3);
+extern UInt VG_(vfprintf) ( VgFile *fp, const HChar *format, va_list vargs )
+ PRINTF_CHECK(2, 0);
+
/* Do a printf-style operation on either the XML
or normal output channel
or gdb output channel, depending on the setting of VG_(clo_xml)
//--- Writing snapshots ---//
//------------------------------------------------------------//
-HChar FP_buf[BUF_LEN];
-
-// XXX: implement f{,n}printf in m_libcprint.c eventually, and use it here.
-// Then change Cachegrind to use it too.
-#define FP(format, args...) ({ \
- VG_(snprintf)(FP_buf, BUF_LEN, format, ##args); \
- FP_buf[BUF_LEN-1] = '\0'; /* Make sure the string is terminated. */ \
- VG_(write)(fd, (void*)FP_buf, VG_(strlen)(FP_buf)); \
-})
+#define FP(format, args...) ({ VG_(fprintf)(fp, format, ##args); })
// Nb: uses a static buffer, each call trashes the last string returned.
static const HChar* make_perc(double x)
return mbuf;
}
-static void pp_snapshot_SXPt(Int fd, SXPt* sxpt, Int depth, HChar* depth_str,
- Int depth_str_len,
- SizeT snapshot_heap_szB, SizeT snapshot_total_szB)
+static void pp_snapshot_SXPt(VgFile *fp, SXPt* sxpt, Int depth,
+ HChar* depth_str, Int depth_str_len,
+ SizeT snapshot_heap_szB, SizeT snapshot_total_szB)
{
Int i, j, n_insig_children_sxpts;
SXPt* child = NULL;
// name always has the same length, which makes truncation
// deterministic and thus makes testing easier.
tl_assert(j <= 18);
+ // FIXME: this whole code block will go away, once VG_(describe_IP)
+ // FIXME: has been fixed; I'm keeping it for now so testcases won't fail
+ HChar FP_buf[BUF_LEN];
VG_(snprintf)(FP_buf, BUF_LEN, "%s\n", ip_desc);
FP_buf[BUF_LEN-18+j-5] = '.'; // "..." at the end make the
FP_buf[BUF_LEN-18+j-4] = '.'; // truncation more obvious.
FP_buf[BUF_LEN-18+j-3] = '.';
FP_buf[BUF_LEN-18+j-2] = '\n'; // The last char is '\n'.
FP_buf[BUF_LEN-18+j-1] = '\0'; // The string is terminated.
- VG_(write)(fd, (void*)FP_buf, VG_(strlen)(FP_buf));
+ VG_(fprintf)(fp, "%s", FP_buf);
// Indent.
tl_assert(depth+1 < depth_str_len-1); // -1 for end NUL char
// Ok, print the child. NB: contents of ip_desc_array will be
// trashed by this recursive call. Doesn't matter currently,
// but worth noting.
- pp_snapshot_SXPt(fd, child, depth+1, depth_str, depth_str_len,
+ pp_snapshot_SXPt(fp, child, depth+1, depth_str, depth_str_len,
snapshot_heap_szB, snapshot_total_szB);
}
}
}
-static void pp_snapshot(Int fd, Snapshot* snapshot, Int snapshot_n)
+static void pp_snapshot(VgFile *fp, Snapshot* snapshot, Int snapshot_n)
{
sanity_check_snapshot(snapshot);
depth_str[0] = '\0'; // Initialise depth_str to "".
FP("heap_tree=%s\n", ( Peak == snapshot->kind ? "peak" : "detailed" ));
- pp_snapshot_SXPt(fd, snapshot->alloc_sxpt, 0, depth_str,
+ pp_snapshot_SXPt(fp, snapshot->alloc_sxpt, 0, depth_str,
depth_str_len, snapshot->heap_szB,
snapshot_total_szB);
Snapshot snapshots_array[],
Int nr_elements)
{
- Int i, fd;
- SysRes sres;
+ Int i;
+ VgFile *fp;
- sres = VG_(open)(massif_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
- VKI_S_IRUSR|VKI_S_IWUSR);
- if (sr_isError(sres)) {
+ fp = VG_(fopen)(massif_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
+ VKI_S_IRUSR|VKI_S_IWUSR);
+ if (fp == NULL) {
// If the file can't be opened for whatever reason (conflict
// between multiple cachegrinded processes?), give up now.
VG_(umsg)("error: can't open output file '%s'\n", massif_out_file );
VG_(umsg)(" ... so profiling results will be missing.\n");
return;
- } else {
- fd = sr_Res(sres);
}
// Print massif-specific options that were used.
for (i = 0; i < nr_elements; i++) {
Snapshot* snapshot = & snapshots_array[i];
- pp_snapshot(fd, snapshot, i); // Detailed snapshot!
+ pp_snapshot(fp, snapshot, i); // Detailed snapshot!
}
- VG_(close) (fd);
+ VG_(fclose) (fp);
}
static void write_snapshots_array_to_file(void)