Author: tim.bunce
Date: Fri Jul  3 08:35:13 2009
New Revision: 796

Modified:
    trunk/Changes
    trunk/NYTProf.xs
    trunk/lib/Devel/NYTProf.pm

Log:
Fixed (rare) overflow bug for 32bit perls.
Fixed discarding of (rare) negative intervals.
Added log=F option to write trace log to a file.
Added sequence numbers to sub calls to aid debugging
Added sanity check warning for negative times from sub profiler


Modified: trunk/Changes
==============================================================================
--- trunk/Changes       (original)
+++ trunk/Changes       Fri Jul  3 08:35:13 2009
@@ -6,6 +6,10 @@

  =head2 Changes in Devel::NYTProf 2.11

+XXX sysops needs docs and more ops
+
+  Fixed (rare) overflow bug for 32bit perls.
+  Fixed discarding of (rare) negative intervals.
    Fixed risk of infinite recursion if trace enabled and
      $SIG{__WARN__} was set to a code reference.
    Fixed recursion depth measurement.
@@ -18,8 +22,8 @@
    Added sysops=1 option which enables profiling of perl opcodes
      that make potentially slow system calls. They appear as xsubs
      in the current package with names prefixed by "CORE:".
-XXX needs docs and more ops

+  Added log=F option to write trace log to a file.
    Added columns to the main source code reports to show
      a count of sub calls and time spent in those calls.


Modified: trunk/NYTProf.xs
==============================================================================
--- trunk/NYTProf.xs    (original)
+++ trunk/NYTProf.xs    Fri Jul  3 08:35:13 2009
@@ -298,6 +298,7 @@
  static Pid_t last_pid;
  static NV cumulative_overhead_ticks = 0.0;
  static NV cumulative_subr_secs = 0.0;
+static UV cumulative_subr_seqn = 0;

  static unsigned int ticks_per_sec = 0;            /* 0 forces error if not  
set */

@@ -342,8 +343,9 @@

  static FILE *logfh;

-void
+static void
  logwarn(const char *pat, ...)
+    __attribute__format__(__printf__,1,2)
  {
      /* we avoid using any perl mechanisms here */
      va_list args;
@@ -1721,8 +1723,7 @@
  {
      int saved_errno;
      char *file;
-    unsigned int elapsed;
-    unsigned int overflow;
+    long elapsed, overflow;

      if (!is_profiling || !profile_stmts) {
          return;
@@ -1891,6 +1892,15 @@
      if (strEQ(option, "file")) {
          strncpy(PROF_output_file, value, MAXPATHLEN);
      }
+    else if (strEQ(option, "log")) {
+        FILE *fp = fopen(value, "a");
+        if (!fp) {
+            logwarn("Can't open log file '%s' for writing: %s\n",
+                value, strerror(errno));
+            return;
+        }
+        logfh = fp;
+    }
      else if (strEQ(option, "start")) {
          if      (strEQ(value,"begin")) profile_start = NYTP_START_BEGIN;
          else if (strEQ(value,"init"))  profile_start = NYTP_START_INIT;
@@ -2056,14 +2066,15 @@

  typedef struct sub_call_start_st
  {
-    time_of_day_t sub_call_time;
+    time_of_day_t initial_call_time;
      char fid_line[50];
      SV *subname_sv;
      AV *sub_av;
      CV *sub_cv;
      int call_depth;
-    NV current_overhead_ticks;
-    NV current_subr_secs;
+    NV initial_overhead_ticks;
+    NV initial_subr_secs;
+    UV seqn;
  } sub_call_start_t;

  static void
@@ -2075,9 +2086,9 @@
      SV *incl_time_sv = *av_fetch(av, NYTP_SCi_INCL_RTIME, 1);
      SV *excl_time_sv = *av_fetch(av, NYTP_SCi_EXCL_RTIME, 1);
      /* statement overheads we've accumulated since we entered the sub */
-    NV overhead_ticks = (int)(cumulative_overhead_ticks -  
sub_call_start->current_overhead_ticks);
+    NV overhead_ticks = cumulative_overhead_ticks -  
sub_call_start->initial_overhead_ticks;
      /* seconds spent in subroutines called by this subroutine */
-    NV called_sub_secs = (cumulative_subr_secs -  
sub_call_start->current_subr_secs);
+    NV called_sub_secs = (cumulative_subr_secs -  
sub_call_start->initial_subr_secs);
      NV incl_subr_sec;
      NV excl_subr_sec;

@@ -2087,26 +2098,26 @@
      }
      else {
          time_of_day_t sub_end_time;
-        unsigned int ticks, overflow;
+        long ticks, overflow;

          /* calculate ticks since we entered the sub */
          get_time_of_day(sub_end_time);
-        get_ticks_between(sub_call_start->sub_call_time, sub_end_time,  
ticks, overflow);
+        get_ticks_between(sub_call_start->initial_call_time, sub_end_time,  
ticks, overflow);

          incl_subr_sec = overflow + (ticks / (NV)ticks_per_sec);
          /* subtract statement measurement overheads */
-        incl_subr_sec -= (overhead_ticks / (NV)ticks_per_sec);
+        incl_subr_sec -= (overhead_ticks / ticks_per_sec);
          /* exclusive = inclusive - time spent in subroutines called by  
this subroutine */
          excl_subr_sec = incl_subr_sec - called_sub_secs;
      }
-
+
      if (trace_level >= 3)
-        logwarn(" <-     %s after %"NVff"s incl - %"NVff"s = %"NVff"s excl  
(sub %g-%g=%g, oh %g-%g=%gt) d%d @%s\n",
-            SvPV_nolen(subname_sv), incl_subr_sec, called_sub_secs,  
excl_subr_sec,
-            cumulative_subr_secs, sub_call_start->current_subr_secs,  
called_sub_secs,
-            cumulative_overhead_ticks,  
sub_call_start->current_overhead_ticks, overhead_ticks,
+        logwarn(" <-     %s %"NVff"s excl = %"NVff"s incl - %"NVff"s  
(%g-%g), oh %g-%g=%gt, d%d @%s #%lu\n",
+            SvPV_nolen(subname_sv), excl_subr_sec, incl_subr_sec,  
called_sub_secs,
+            cumulative_subr_secs, sub_call_start->initial_subr_secs,
+            cumulative_overhead_ticks,  
sub_call_start->initial_overhead_ticks, overhead_ticks,
              (int)sub_call_start->call_depth,
-            sub_call_start->fid_line);
+            sub_call_start->fid_line, sub_call_start->seqn);

      /* only count inclusive time for the outer-most calls */
      if (sub_call_start->call_depth <= 1) {
@@ -2235,9 +2246,10 @@
          int saved_errno = errno;
          if (!profile_stmts)
              reinit_if_forked(aTHX);
-        get_time_of_day(sub_call_start.sub_call_time);
-        sub_call_start.current_overhead_ticks = cumulative_overhead_ticks;
-        sub_call_start.current_subr_secs = cumulative_subr_secs;
+        get_time_of_day(sub_call_start.initial_call_time);
+        sub_call_start.initial_overhead_ticks = cumulative_overhead_ticks;
+        sub_call_start.initial_subr_secs = cumulative_subr_secs;
+        sub_call_start.seqn = ++cumulative_subr_seqn;
          SETERRNO(saved_errno, 0);
      }

@@ -2246,8 +2258,17 @@
       * and returns the first op *within* the sub (typically a  
nextstate/dbstate).
       * for XS subs pp_entersub executes the entire sub
       * and returns the op *after* the sub (PL_op->op_next)
+     * Other ops we profile (eg sysops) act like xsubs.
+     */
+    /* May croak (in xsub, in sysops, or in pp_entersub e.g., sub not  
found).
+     * If it does croak then currently we don't record the call at all.
+     * Such cases are relatively rare, so it's not a significant problem.
+     * (The xsub case is probably the most significant, especially if the
+     * xsub calls back into perl code which then croaks. In that case the
+     * entersub to perl, and any calls made by the perl code, will get  
recorded
+     * but the xsub call itself won't)
       */
-    op = run_original_op(op_type);            /* may croak */
+    op = run_original_op(op_type);

      if (profile_sub_call) {
          int saved_errno = errno;
@@ -2404,11 +2425,12 @@
          sub_call_start.call_depth = (cv) ? CvDEPTH(cv)+(is_xs?1:0) : 1;

          if (trace_level >= 2)
-            fprintf(stderr, " ->%s %s from %d:%d (d%d, oh %gt, sub %gs)\n",
+            fprintf(stderr, " ->%s %s from %d:%d (d%d, oh %"NVff"t,  
sub %"NVff"s) #%lu\n",
                  (is_xs) ? is_xs : " sub", subname_pv, fid, line,
                  sub_call_start.call_depth,
-                sub_call_start.current_overhead_ticks,
-                sub_call_start.current_subr_secs
+                sub_call_start.initial_overhead_ticks,
+                sub_call_start.initial_subr_secs,
+                sub_call_start.seqn
              );

          if (profile_subs) {
@@ -2916,6 +2938,7 @@
          while (NULL != (sv = hv_iternextsv(fid_lines_hv, &fid_line_string,  
&fid_line_len))) {
              NV sc[NYTP_SCi_elements];
              AV *av = (AV *)SvRV(sv);
+            int trace = (trace_level >= 3);

              unsigned int fid = 0, line = 0;
              (void)sscanf(fid_line_string, "%u:%u", &fid, &line);
@@ -2931,7 +2954,13 @@
              sc[NYTP_SCi_REC_DEPTH]  = output_uv_from_av(aTHX_ av,  
NYTP_SCi_REC_DEPTH , 0) * 1.0;
              output_str(sub_name, sub_name_len);

-            if (trace_level >= 3)
+            /* sanity check - early warning */
+            if (sc[NYTP_SCi_INCL_RTIME] < 0.0 || sc[NYTP_SCi_EXCL_RTIME] <  
0.0) {
+                logwarn("%s call has negative time!", sub_name);
+                trace = 1;
+            }
+
+            if (trace)
                  logwarn("%s called by %u:%u: count %"NVff" (i%"NVff"s  
e%"NVff"s u%"NVff"s s%"NVff"s, d%"NVff" ri%"NVff"s)\n",
                      sub_name, fid, line, sc[NYTP_SCi_CALL_COUNT],
                      sc[NYTP_SCi_INCL_RTIME], sc[NYTP_SCi_EXCL_RTIME],

Modified: trunk/lib/Devel/NYTProf.pm
==============================================================================
--- trunk/lib/Devel/NYTProf.pm  (original)
+++ trunk/lib/Devel/NYTProf.pm  Fri Jul  3 08:35:13 2009
@@ -272,7 +272,13 @@

  =head2 trace=N

-Set trace level to N. 0 is off (the default). Higher values cause more  
detailed trace output.
+Set trace level to N. 0 is off (the default). Higher values cause more  
detailed
+trace output. Trace output is written to STDERR or wherever the L</log=F>
+option has specified.
+
+=head2 log=F
+
+Specify the name of the file that L</trace=N> output should be written to.

  =head2 start=...


--~--~---------~--~----~------------~-------~--~----~
You've received this message because you are subscribed to
the Devel::NYTProf Development User group.

Group hosted at:  http://groups.google.com/group/develnytprof-dev
Project hosted at:  http://perl-devel-nytprof.googlecode.com
CPAN distribution:  http://search.cpan.org/dist/Devel-NYTProf

To post, email:  [email protected]
To unsubscribe, email:  [email protected]
-~----------~----~----~----~------~----~------~--~---

Reply via email to