]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add a simple progress-reporting facility.
authorIvo Raisr <ivosh@ivosh.net>
Fri, 19 Jan 2018 16:12:34 +0000 (16:12 +0000)
committerIvo Raisr <ivosh@ivosh.net>
Sat, 20 Jan 2018 19:56:02 +0000 (19:56 +0000)
Fixes BZ#384633.
Patch by: Julian Seward <jseward@acm.org>

NEWS
coregrind/m_libcproc.c
coregrind/m_main.c
coregrind/m_options.c
coregrind/m_scheduler/scheduler.c
coregrind/m_transtab.c
coregrind/pub_core_options.h
docs/xml/manual-core.xml
include/pub_tool_libcproc.h
include/vki/vki-linux.h
none/tests/cmdline2.stdout.exp

diff --git a/NEWS b/NEWS
index 46c4db2c242e2c1a8329ed5cf05b6fb1a7317f75..ac73ddee0bc4fe2911eab662239b3397b97497d8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -72,6 +72,7 @@ where XXXXXX is the bug number as listed below.
 384096  Mention AddrCheck at Memcheck's command line option --undef-value-errors=no
 384526  reduce number of spill instructions generated by VEX register allocator v3
 384584  Callee saved registers listed first for AMD64, X86, and PPC architectures
+384633  Add a simple progress-reporting facility
 384987  VEX register allocator: allocate caller-save registers for short lived vregs
 385182  PPC64 is missing support for the DSCR
 385207  PPC64, generate_store_FPRF() generates too many Iops
index afcc11729d0739c8f84ceb1c6896a821ae182b2c..97a4fc53470d9dcc0cd7e22a4fe0d6cea71269aa 100644 (file)
@@ -958,6 +958,40 @@ Int VG_(gettimeofday)(struct vki_timeval *tv, struct vki_timezone *tz)
    return -1;
 }
 
+UInt VG_(get_user_milliseconds)(void)
+{
+   UInt res = 0;
+#  if defined(VGO_linux)
+   {
+      struct vki_rusage ru;
+      VG_(memset)(&ru, 0, sizeof(ru));
+      SysRes sr = VG_(do_syscall2)(__NR_getrusage, VKI_RUSAGE_SELF, (UWord)&ru);
+      if (!sr_isError(sr)) {
+         res = ru.ru_utime.tv_sec * 1000 + ru.ru_utime.tv_usec / 1000;
+      }
+   }
+
+#  elif defined(VGO_solaris)
+   {
+      struct vki_rusage ru;
+      VG_(memset)(&ru, 0, sizeof(ru));
+      SysRes sr = VG_(do_syscall2)(__NR_rusagesys, VKI__RUSAGESYS_GETRUSAGE,
+                                   (UWord) &ru);
+      if (!sr_isError(sr)) {
+         res = ru.ru_utime.tv_sec * 1000 + ru.ru_utime.tv_usec / 1000;
+      }
+   }
+
+#  elif defined(VGO_darwin)
+   res = 0;
+
+#  else
+#    error "Unknown OS"
+#  endif
+
+   return res;
+}
+
 
 /* ---------------------------------------------------------------------
    atfork()
index a7574c3e5be23600626e3a9984a85e1219b344eb..bf4a71284671e34a03d62d5ed20754c6db15c508 100644 (file)
@@ -258,6 +258,8 @@ static void usage_NORETURN ( Bool debug_help )
 "                              heap blocks allocated for Valgrind internal use (in bytes) [4]\n"
 "    --wait-for-gdb=yes|no     pause on startup to wait for gdb attach\n"
 "    --sym-offsets=yes|no      show syms in form 'name+offset'? [no]\n"
+"    --progress-interval=<number>  report progress every <number>\n"
+"                                  CPU seconds [0, meaning disabled]\n"
 "    --command-line-only=no|yes  only use command line options [no]\n"
 "\n"
 "  Vex options for all Valgrind tools:\n"
@@ -671,6 +673,8 @@ void main_process_cmd_line_options( void )
       else if VG_BOOL_CLO(arg, "--trace-syscalls",   VG_(clo_trace_syscalls)) {}
       else if VG_BOOL_CLO(arg, "--wait-for-gdb",     VG_(clo_wait_for_gdb)) {}
       else if VG_BOOL_CLO(arg, "--sym-offsets",      VG_(clo_sym_offsets)) {}
+      else if VG_BINT_CLO(arg, "--progress-interval",
+                               VG_(clo_progress_interval), 0, 3600) {}
       else if VG_BOOL_CLO(arg, "--read-inline-info", VG_(clo_read_inline_info)) {}
       else if VG_BOOL_CLO(arg, "--read-var-info",    VG_(clo_read_var_info)) {}
 
index 72173ddfa2bed7f7fc82cde2dc0944590fdd5a6a..67eed342bad17e4c295cb823066addf55481d770 100644 (file)
@@ -110,6 +110,8 @@ enum FairSchedType
        VG_(clo_fair_sched)     = disable_fair_sched;
 Bool   VG_(clo_trace_sched)    = False;
 Bool   VG_(clo_profile_heap)   = False;
+UInt   VG_(clo_progress_interval) = 0; /* in seconds, 1 .. 3600,
+                                          or 0 == disabled */
 Int    VG_(clo_core_redzone_size) = CORE_REDZONE_DEFAULT_SZB;
 // A value != -1 overrides the tool-specific value
 // VG_(needs_malloc_replacement).tool_client_redzone_szB
index 54b8008d61c46ed3e70f8a2031ca9bce392947b3..2ffcf4b8661b25db82457c0c95a0788e3365f8cd 100644 (file)
@@ -172,6 +172,56 @@ static struct sched_lock *the_BigLock;
    Helper functions for the scheduler.
    ------------------------------------------------------------------ */
 
+static void maybe_progress_report ( UInt reporting_interval_seconds )
+{
+   /* This is when the next report is due, in user cpu milliseconds since
+      process start.  This is a global variable so this won't be thread-safe
+      if Valgrind is ever made multithreaded.  For now it's fine. */
+   static UInt next_report_due_at = 0;
+
+   /* First of all, figure out whether another report is due.  It
+      probably isn't. */
+   UInt user_ms = VG_(get_user_milliseconds)();
+   if (LIKELY(user_ms < next_report_due_at))
+      return;
+
+   Bool first_ever_call = next_report_due_at == 0;
+
+   /* A report is due.  First, though, set the time for the next report. */
+   next_report_due_at += 1000 * reporting_interval_seconds;
+
+   /* If it's been an excessively long time since the last check, we
+      might have gone more than one reporting interval forward.  Guard
+      against that. */
+   while (next_report_due_at <= user_ms)
+      next_report_due_at += 1000 * reporting_interval_seconds;
+
+   /* Also we don't want to report anything on the first call, but we
+      have to wait till this point to leave, so that we set up the
+      next-call time correctly. */
+   if (first_ever_call)
+      return;
+
+   /* Print the report. */
+   UInt   user_cpu_seconds  = user_ms / 1000;
+   UInt   wallclock_seconds = VG_(read_millisecond_timer)() / 1000;
+   Double millionEvCs   = ((Double)bbs_done) / 1000000.0;
+   Double thousandTIns  = ((Double)VG_(get_bbs_translated)()) / 1000.0;
+   Double thousandTOuts = ((Double)VG_(get_bbs_discarded_or_dumped)()) / 1000.0;
+   UInt   nThreads      = VG_(count_living_threads)();
+
+   if (VG_(clo_verbosity) > 0) {
+      VG_(dmsg)("PROGRESS: U %'us, W %'us, %.1f%% CPU, EvC %.2fM, "
+                "TIn %.1fk, TOut %.1fk, #thr %u\n",
+                user_cpu_seconds, wallclock_seconds,
+                100.0
+                   * (Double)(user_cpu_seconds)
+                   / (Double)(wallclock_seconds == 0 ? 1 : wallclock_seconds),
+                millionEvCs,
+                thousandTIns, thousandTOuts, nThreads);
+   }
+}
+
 static
 void print_sched_event ( ThreadId tid, const HChar* what )
 {
@@ -1315,6 +1365,11 @@ VgSchedReturnCode VG_(scheduler) ( ThreadId tid )
         scheduler_sanity(tid);
         VG_(sanity_check_general)(False);
 
+         /* Possibly make a progress report */
+         if (UNLIKELY(VG_(clo_progress_interval) > 0)) {
+            maybe_progress_report( VG_(clo_progress_interval) );
+         }
+
         /* Look for any pending signals for this thread, and set them up
            for delivery */
         VG_(poll_signals)(tid);
index fa0a8683c5ff68c6161659d1f27dfb5caebb4c13..6ef9ceae2951b6fa83b99d2b9efc26a8d55589d3 100644 (file)
@@ -2565,6 +2565,11 @@ UInt VG_(get_bbs_translated) ( void )
    return n_in_count;
 }
 
+UInt VG_(get_bbs_discarded_or_dumped) ( void )
+{
+   return n_disc_count + n_dump_count;
+}
+
 void VG_(print_tt_tc_stats) ( void )
 {
    VG_(message)(Vg_DebugMsg,
index cc6bb835c553818fbcde0a76c4dab0d59cdd88ca..3bae7f3f19881bea63115f5efa3988de8320776a 100644 (file)
@@ -201,6 +201,8 @@ extern enum FairSchedType VG_(clo_fair_sched);
 extern Bool  VG_(clo_trace_sched);
 /* DEBUG: do heap profiling?  default: NO */
 extern Bool  VG_(clo_profile_heap);
+// DEBUG: report progress every N seconds (1 .. 3600)
+extern UInt VG_(clo_progress_interval);
 #define MAX_REDZONE_SZB 128
 // Maximum for the default values for core arenas and for client
 // arena given by the tool.
index 6a038829ee64e223a73f0dca117654061d05e982..48321acd5bd77488818ce0c2c5821a59092ddf16 100644 (file)
@@ -2581,6 +2581,60 @@ need to use them.</para>
    </listitem>
   </varlistentry>
 
+  <varlistentry id="opt.progress-interval" xreflabel="--progress-interval">
+    <term>
+      <option><![CDATA[--progress-interval=<number> [default: 0, meaning 'disabled'] ]]></option>
+    </term>
+    <listitem>
+      <para>This is an enhancement to Valgrind's debugging output.  It is
+        unlikely to be of interest to end users.</para>
+      <para>When <varname>number</varname> is set to a non-zero value,
+        Valgrind will print a one-line progress summary
+        every <varname>number</varname> seconds.  Valid settings
+        for <varname>number</varname> are between 0 and 3600
+        inclusive.  Here's some example output
+        with <varname>number</varname>
+        set to 10:
+        <programlisting><![CDATA[
+PROGRESS: U 110s, W 113s, 97.3% CPU, EvC 414.79M, TIn 616.7k, TOut 0.5k, #thr 67
+PROGRESS: U 120s, W 124s, 96.8% CPU, EvC 505.27M, TIn 636.6k, TOut 3.0k, #thr 64
+PROGRESS: U 130s, W 134s, 97.0% CPU, EvC 574.90M, TIn 657.5k, TOut 3.0k, #thr 63
+]]></programlisting>
+        Each line shows:
+      <itemizedlist>
+        <listitem><varname>U</varname>: total user time</listitem>
+        <listitem><varname>W</varname>: total wallclock time</listitem>
+        <listitem><varname>CPU</varname>: overall average cpu use</listitem>
+        <listitem><varname>EvC</varname>: number of event checks.  An event
+         check is a backwards branch in the simulated program, so this is a
+         measure of forward progress of the program</listitem>
+        <listitem><varname>TIn</varname>: number of code blocks instrumented
+          by the JIT</listitem>
+        <listitem><varname>TOut</varname>: number of instrumented code
+          blocks that have been thrown away</listitem>
+        <listitem><varname>#thr</varname>: number of threads in the
+        program</listitem>
+      </itemizedlist>
+      From the progress of these, it is possible to observe:
+      <itemizedlist>
+        <listitem>when the program is compute bound (<varname>TIn</varname>
+          rises slowly, <varname>EvC</varname> rises rapidly)</listitem>
+        <listitem>when the program is in a spinloop
+          (<varname>TIn</varname>/<varname>TOut</varname>
+          fixed, <varname>EvC</varname> rises rapidly)</listitem>
+        <listitem>when the program is JIT-bound (<varname>TIn</varname>
+          rises rapidly)</listitem>
+        <listitem>when the program is rapidly discarding code
+          (<varname>TOut</varname> rises rapidly)</listitem>
+        <listitem>when the program is about to achieve some expected state
+          (<varname>EvC</varname> arrives at some value you
+          expect)</listitem>
+        <listitem> when the program is idling (<varname>U</varname> rises
+          more slowly than <varname>W</varname>)</listitem>
+      </itemizedlist>
+      </para>
+   </listitem>
+  </varlistentry>
 
 </variablelist>
 <!-- end of xi:include in the manpage -->
index a3a186bc65e24e21d2a5c2de59ab72ce3894a614..96b6d6838ef8464147e24019b4f660dc9f2bf23a 100644 (file)
@@ -98,12 +98,17 @@ extern Int VG_(getegid) ( void );
    Timing
    ------------------------------------------------------------------ */
 
-// Returns the number of milliseconds passed since the progam started
+// Returns the number of milliseconds passed since the program started
 // (roughly;  it gets initialised partway through Valgrind's initialisation
-// steps).
+// steps).  This is wallclock time.
 extern UInt VG_(read_millisecond_timer) ( void );
+
 extern Int  VG_(gettimeofday)(struct vki_timeval *tv, struct vki_timezone *tz);
 
+// Returns the number of milliseconds of user cpu time we have used,
+// as reported by 'getrusage'.
+extern UInt VG_(get_user_milliseconds)(void);
+
 /* ---------------------------------------------------------------------
    atfork
    ------------------------------------------------------------------ */
index 4840a53e297641a420b952a2e597ecc70b5bab8a..faacf7fb379f92702ffa8a3dd58e9b9086c7a276 100644 (file)
@@ -971,6 +971,11 @@ struct vki_sctp_getaddrs {
 // From linux-2.6.8.1/include/linux/resource.h
 //----------------------------------------------------------------------
 
+#define VKI_RUSAGE_SELF     0
+#define VKI_RUSAGE_CHILDREN (-1)
+#define VKI_RUSAGE_BOTH     (-2)        /* sys_wait4() uses this */
+#define VKI_RUSAGE_THREAD   1           /* only the calling thread */
+
 struct vki_rusage {
        struct vki_timeval ru_utime;    /* user time used */
        struct vki_timeval ru_stime;    /* system time used */
index 2599a1b2f11389626e1b7886d7b85eaf5ceef326..fb42abb49abf734e993f9c832c7167034bd2b2ba 100644 (file)
@@ -170,6 +170,8 @@ usage: valgrind [options] prog-and-args
                               heap blocks allocated for Valgrind internal use (in bytes) [4]
     --wait-for-gdb=yes|no     pause on startup to wait for gdb attach
     --sym-offsets=yes|no      show syms in form 'name+offset'? [no]
+    --progress-interval=<number>  report progress every <number>
+                                  CPU seconds [0, meaning disabled]
     --command-line-only=no|yes  only use command line options [no]
 
   Vex options for all Valgrind tools: