Author: tim.bunce
Date: Fri Jul 17 16:12:56 2009
New Revision: 837

Modified:
    trunk/Changes
    trunk/NYTProf.xs

Log:
Started work refactoring to (finally) profile goto &sub sanely.
(That's the last significant crack in the subroutine call tree.)


Modified: trunk/Changes
==============================================================================
--- trunk/Changes       (original)
+++ trunk/Changes       Fri Jul 17 16:12:56 2009
@@ -9,6 +9,7 @@
  XXX slowops needs docs and more ops
  XXX subroutine profiler docs need update
  XXX doc findcaller option
+XXX note here and doc goto behaviour

    Note: The file format has changed. Old files can't be read.


Modified: trunk/NYTProf.xs
==============================================================================
--- trunk/NYTProf.xs    (original)
+++ trunk/NYTProf.xs    Fri Jul 17 16:12:56 2009
@@ -2370,6 +2370,147 @@
  }


+static I32
+subr_entry_setup(pTHX, COP *prev_cop, subr_entry_t *clone_subr_entry)
+{
+    subr_entry_t *subr_entry;
+    I32 prev_subr_entry_ix = subr_entry_ix;
+    subr_entry_t *caller_subr_entry =  
subr_entry_ix_ptr(prev_subr_entry_ix);
+    char *found_caller_by;
+    char *file;
+    dSP;
+    SV *sub_sv = *SP;
+
+    if (trace_level >= 99) {
+        logwarn("entering sub\n");
+        /* crude, but the only way to deal with the miriad logic at the
+            * start of pp_entersub (which ought to be available as  
separate sub)
+            */
+        sv_dump(sub_sv);
+    }
+
+    /* allocate struct to save stack (very efficient) */
+    /* XXX "warning: cast from pointer to integer of different size" with  
use64bitall=define */
+    subr_entry_ix = SSNEWa(sizeof(*subr_entry), MEM_ALIGNBYTES);
+    subr_entry = subr_entry_ix_ptr(subr_entry_ix);
+    Zero(subr_entry, 1, sizeof(subr_entry_t));
+    subr_entry->prev_subr_entry_ix = prev_subr_entry_ix;
+
+    get_time_of_day(subr_entry->initial_call_time);
+    subr_entry->initial_overhead_ticks = cumulative_overhead_ticks;
+    subr_entry->initial_subr_secs      = cumulative_subr_secs;
+    subr_entry->subr_call_seqn         = ++cumulative_subr_seqn;
+    subr_entry->called_subnam_sv       = &PL_sv_undef; /* see  
incr_sub_inclusive_time */
+    subr_entry->called_is_xs           = "?"; /* we don't know yet */
+
+    file = OutCopFILE(prev_cop);
+    subr_entry->caller_fid = (file == last_executed_fileptr)
+        ? last_executed_fid
+        : get_file_id(aTHX_ file, strlen(file), NYTP_FIDf_VIA_SUB);
+    subr_entry->caller_line = CopLINE(prev_cop);
+
+    /* Gather details about the calling subroutine */
+    if (clone_subr_entry) {
+        subr_entry->caller_subpkg_pv = clone_subr_entry->called_subpkg_pv;
+        subr_entry->caller_subnam_sv =  
SvREFCNT_inc(clone_subr_entry->called_subnam_sv);
+        found_caller_by = "(cloned)";
+    }
+    else
+    /* Should we calculate the caller or can we reuse the  
caller_subr_entry?
+     * Sometimes we'll have a caller_subr_entry but it won't have the name  
yet.
+     * For example if the caller is an xsub or slowop that's callbacked  
into perl.
+     */
+    if (profile_findcaller             /* user wants us to calculate each  
time */
+    || !caller_subr_entry                     /* we don't have a caller  
struct */
+    || !caller_subr_entry->called_subpkg_pv   /* we don't have caller  
details  */
+    || !SvOK(caller_subr_entry->called_subnam_sv)
+    ) {
+        /* get the current CV and determine the current sub name from that  
*/
+        CV *caller_cv = current_cv(aTHX_ cxstack_ix, NULL);
+        subr_entry->caller_subnam_sv = newSV(0); /* XXX add cache/stack  
thing for these SVs */
+
+        if (caller_cv == PL_main_cv) {
+            subr_entry->caller_subpkg_pv = "main";
+            sv_setpv(subr_entry->caller_subnam_sv, "BEGIN");
+        }
+        else {
+            HV *stash_hv = NULL;
+            GV *gv = CvGV(caller_cv);
+            GV *egv = GvEGV(gv);
+            if (!egv)
+                gv = egv;
+
+            if (gv && (stash_hv = GvSTASH(gv))) {
+                subr_entry->caller_subpkg_pv = HvNAME(stash_hv);
+                 
sv_setpvn(subr_entry->caller_subnam_sv,GvNAME(gv),GvNAMELEN(gv));
+            }
+            else {
+                logwarn("Can't determine name of calling sub (GV %p,  
Stash %p, CV flags %d) at %s line %d\n",
+                    gv, stash_hv, (int)CvFLAGS(caller_cv),
+                    OutCopFILE(prev_cop), (int)CopLINE(prev_cop));
+                sv_dump((SV*)caller_cv);
+
+                subr_entry->caller_subpkg_pv = "__UNKNOWN__";
+                sv_setpv(subr_entry->caller_subnam_sv, "__UNKNOWN__");
+            }
+        }
+        found_caller_by = (profile_findcaller) ? "" : "(calculated)";
+    }
+    else {
+        subr_entry->caller_subpkg_pv = caller_subr_entry->called_subpkg_pv;
+        subr_entry->caller_subnam_sv =  
SvREFCNT_inc(caller_subr_entry->called_subnam_sv);
+        found_caller_by = "(inherited)";
+    }
+
+    if (trace_level >= 4)
+        logwarn("Making sub call at %u:%d from %s::%s %s\n",
+            subr_entry->caller_fid, subr_entry->caller_line,
+            subr_entry->caller_subpkg_pv,
+            SvPV_nolen(subr_entry->caller_subnam_sv),
+            found_caller_by
+        );
+
+    return subr_entry_ix;
+}
+
+
+static OP *
+pp_goto_profiler(pTHX)
+{
+    /* we don't actually profile the goto, just do some housekeeping... */
+    dSP;
+    OP *op;
+    SV *sv = *SP; /* top of stack */
+    int is_goto_sub = (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV);
+    subr_entry_t orig_subr_entry;
+
+    /* goto &sub acts like a return followed by a call,
+     * While this op is executing the subr_entry pushed onto the savestack
+     * by pp_subcall_profiler will be 'completed' so the profiling of that  
call
+     * will be handled naturally for us. So far so good.
+     */
+    if (is_goto_sub) {
+        /*
+        memcpy(&orig_subr_entry, XXX);
+        refcnt inc and mortalize
+        */
+    }
+
+    op = run_original_op(PL_op->op_type);   /* may croak */
+
+    /* If this was a goto &sub then op is the CvSTART of the called sub.
+     * What we need to do here is handle the entry to a new sub as if
+     * it was valled via pp_subcall_profiler()
+     */
+    if (0 && is_goto_sub) {
+        /* XXX call subr_entry_setup() plus some post-entry code */
+        subr_entry_setup(aTHX_ PL_curcop, &orig_subr_entry);
+    }
+
+    return op;
+}
+
+
  static OP *
  pp_entersub_profiler(pTHX)
  {
@@ -2391,111 +2532,24 @@
      /* pp_entersub can be called with PL_op->op_type==0 */
      OPCODE op_type = (is_sop) ? PL_op->op_type : OP_ENTERSUB;
      dSP;
-    SV *sub_sv = NULL;
-    subr_entry_t *subr_entry = NULL;
+    SV *sub_sv = *SP;
      int profile_sub_call = (profile_subs && is_profiling
          /* don't profile calls to non-existant import() methods */
          && !(op_type==OP_ENTERSUB && *SP == &PL_sv_yes)
      );

      if (profile_sub_call) {
-        I32 prev_subr_entry_ix = subr_entry_ix;
-        subr_entry_t *caller_subr_entry =  
subr_entry_ix_ptr(prev_subr_entry_ix);
-        char *found_caller_by;
-        char *file;
          int saved_errno = errno;
-        sub_sv = *SP;
+
          if (!profile_stmts)
              reinit_if_forked(aTHX);

-        if (trace_level >= 99) {
-            logwarn("entering sub\n");
-            /* crude, but the only way to deal with the miriad logic at the
-             * start of pp_entersub (which ought to be available as  
separate sub)
-             */
-            sv_dump(sub_sv);
-        }
-
-        /* allocate struct to save stack (very efficient) */
-        /* XXX "warning: cast from pointer to integer of different size"  
with use64bitall=define */
-        subr_entry_ix = SSNEWa(sizeof(*subr_entry), MEM_ALIGNBYTES);
-        subr_entry = subr_entry_ix_ptr(subr_entry_ix);
-        Zero(subr_entry, 1, sizeof(subr_entry_t));
-        subr_entry->prev_subr_entry_ix = prev_subr_entry_ix;
-
-        get_time_of_day(subr_entry->initial_call_time);
-        subr_entry->initial_overhead_ticks = cumulative_overhead_ticks;
-        subr_entry->initial_subr_secs      = cumulative_subr_secs;
-        subr_entry->subr_call_seqn         = ++cumulative_subr_seqn;
-
-        file = OutCopFILE(prev_cop);
-        subr_entry->caller_fid = (file == last_executed_fileptr)
-            ? last_executed_fid
-            : get_file_id(aTHX_ file, strlen(file), NYTP_FIDf_VIA_SUB);
-        subr_entry->caller_line = CopLINE(prev_cop);
-
-        /* Gather details about the caller */
-        /* Should we calculate the caller or can we reuse the  
caller_subr_entry?
-         * Sometimes we'll have a caller_subr_entry but it won't have the  
name yet.
-         * For example if the caller is an xsub or slowop that's  
callbacked into perl.
-         */
-        if (profile_findcaller             /* user wants us to calculate  
each time */
-        || !caller_subr_entry                     /* we don't have a  
caller struct */
-        || !caller_subr_entry->called_subpkg_pv   /* we don't have caller  
details  */
-        || !SvOK(caller_subr_entry->called_subnam_sv)
-        ) {
-            /* get the current CV and determine the current sub name from  
that */
-            CV *caller_cv = current_cv(aTHX_ cxstack_ix, NULL);
-            subr_entry->caller_subnam_sv = newSV(0); /* XXX add  
cache/stack thing for these SVs */
-
-            if (caller_cv == PL_main_cv) {
-                subr_entry->caller_subpkg_pv = "main";
-                sv_setpv(subr_entry->caller_subnam_sv, "BEGIN");
-            }
-            else {
-                HV *stash_hv = NULL;
-                GV *gv = CvGV(caller_cv);
-                GV *egv = GvEGV(gv);
-                if (!egv)
-                    gv = egv;
-
-                if (gv && (stash_hv = GvSTASH(gv))) {
-                    subr_entry->caller_subpkg_pv = HvNAME(stash_hv);
-                     
sv_setpvn(subr_entry->caller_subnam_sv,GvNAME(gv),GvNAMELEN(gv));
-                }
-                else {
-                    logwarn("Can't determine name of calling sub (GV %p,  
Stash %p, CV flags %d) at %s line %d\n",
-                        gv, stash_hv, (int)CvFLAGS(caller_cv),
-                        OutCopFILE(prev_cop), (int)CopLINE(prev_cop));
-                    sv_dump((SV*)caller_cv);
-
-                    subr_entry->caller_subpkg_pv = "__UNKNOWN__";
-                    sv_setpv(subr_entry->caller_subnam_sv, "__UNKNOWN__");
-                }
-            }
-            found_caller_by = (profile_findcaller) ? "" : "(calculated)";
-        }
-        else {
-            subr_entry->caller_subpkg_pv =  
caller_subr_entry->called_subpkg_pv;
-            subr_entry->caller_subnam_sv =  
SvREFCNT_inc(caller_subr_entry->called_subnam_sv);
-            found_caller_by = "(inherited)";
-        }
-
-        if (trace_level >= 4)
-            logwarn("Making sub at %u:%d from %s::%s %s\n",
-                subr_entry->caller_fid, subr_entry->caller_line,
-                subr_entry->caller_subpkg_pv,
-                SvPV_nolen(subr_entry->caller_subnam_sv),
-                found_caller_by
-            );
-
-        /* initialize items we'll set later */
-        subr_entry->called_subnam_sv = &PL_sv_undef; /* see  
incr_sub_inclusive_time */
-        subr_entry->called_is_xs = "?"; /* we don't know yet */
+        subr_entry_ix = subr_entry_setup(aTHX, prev_cop, NULL);

          SETERRNO(saved_errno, 0);
      }

+
      /*
       * For normal subs, pp_entersub enters the sub and returns the
       * first op *within* the sub (typically a nextstate/dbstate).
@@ -2514,6 +2568,7 @@
          char *stash_name = NULL;
          CV *called_cv;
          char *is_xs;
+        subr_entry_t *subr_entry = subr_entry_ix_ptr(subr_entry_ix);

          /* push a destructor hook onto the context stack to ensure we  
account
           * for time in the sub when we leave it, even if via an exception.
@@ -2904,6 +2959,7 @@
      if (!pkg_fids_hv)
          pkg_fids_hv = newHV();
      PL_ppaddr[OP_ENTERSUB] = pp_entersub_profiler;
+    PL_ppaddr[OP_GOTO] = pp_goto_profiler;

      if (!PL_checkav) PL_checkav = newAV();
      if (!PL_initav)  PL_initav  = newAV();

--~--~---------~--~----~------------~-------~--~----~
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