Author: tim.bunce
Date: Tue Jun 30 03:48:22 2009
New Revision: 784

Modified:
    trunk/Changes
    trunk/NYTProf.xs

Log:
Added sysops=1 option which enables profiling of perl opcodes
that make potentially slow system calls. Just a rough first version for now.
pp_sysop_profiler needs to be refactored with pp_sub_profiler next.


Modified: trunk/Changes
==============================================================================
--- trunk/Changes       (original)
+++ trunk/Changes       Tue Jun 30 03:48:22 2009
@@ -8,6 +8,10 @@

    Added treemap view of package and subroutine times, with drill-down.

+  Added sysops=1 option which enables profiling of perl opcodes
+    that make potentially slow system calls.
+XXX needs docs and more ops
+
  =head2 Changes in Devel::NYTProf 2.10 (svn r774) 18th June 2009

    Fixed call count for XSubs that was one too high.

Modified: trunk/NYTProf.xs
==============================================================================
--- trunk/NYTProf.xs    (original)
+++ trunk/NYTProf.xs    Tue Jun 30 03:48:22 2009
@@ -242,7 +242,9 @@
  #define profile_clock options[8].option_value
      { "clock", -1 },
  #define profile_stmts options[9].option_value
-    { "stmts", 1 }                               /* statement exclusive  
times */
+    { "stmts", 1 },                              /* statement exclusive  
times */
+#define profile_sysops options[10].option_value
+    { "sysops", 0 }                              /* opcodes that make slow  
system calls */
  };

  /* time tracking */
@@ -2422,6 +2424,122 @@
  }


+static OP *
+pp_sysop_profiler(pTHX)                           /* handles ops that make  
slow system calls */
+{
+    OP *next_op;
+    COP *prev_cop = PL_curcop;                    /* not PL_curcop_nytprof  
here */
+    sub_call_start_t sysop_call_start;
+    int profile_sysop_call = (profile_subs && is_profiling);
+
+    if (profile_sysop_call) {
+        int saved_errno = errno;
+        if (!profile_stmts)
+            reinit_if_forked(aTHX);
+        get_time_of_day(sysop_call_start.sub_call_time);
+        sysop_call_start.current_overhead_ticks =  
cumulative_overhead_ticks;
+        sysop_call_start.current_subr_secs = cumulative_subr_secs;
+        SETERRNO(saved_errno, 0);
+    }
+
+    next_op = run_original_op(PL_op->op_type);            /* may croak */
+
+    if (profile_sysop_call) {
+        int saved_errno = errno;
+
+        /* get line, file, and fid for statement *before* the call */
+
+        char *file = OutCopFILE(prev_cop);
+        unsigned int fid;
+        /* XXX could use same closest_cop as DB_stmt() but it doesn't seem
+         * to be needed here. Line is 0 only when call is from embedded
+         * C code like mod_perl (at least in my testing so far)
+         */
+        int line = CopLINE(prev_cop);
+        char fid_line_key[50];
+        int fid_line_key_len;
+        char *stash_name = "CORE::GLOBAL";
+        SV *subname_sv = newSV(0);
+        char *subname_pv;
+        SV *sv_tmp;
+
+        /* XXX not quite right, but close enough for now */
+        sv_setpvf(subname_sv, "%s::%s", stash_name, OP_NAME_safe(PL_op));
+        subname_pv = SvPV_nolen(subname_sv);
+
+        fid = (file == last_executed_fileptr)
+            ? last_executed_fid
+            : get_file_id(aTHX_ file, strlen(file), NYTP_FIDf_VIA_SUB);
+        fid_line_key_len = sprintf(fid_line_key, "%u:%d", fid, line);
+
+        /* { called_subname => { "fid:line" => [ count, incl_time ] } } */
+        sv_tmp = *hv_fetch(sub_callers_hv, subname_pv,
+            (I32)SvCUR(subname_sv), 1);
+
+        /* XXX fid:line can be ambiguous, e.g sub foo { return sub { ... }  
}
+         * We could add subname_sv to the [ count, incl_time ] array
+         * and check it on each call. To improve performance we could also
+         * add the op and so avoid the string compare if the op's are the  
same.
+         * If there's a call with a different subname_sv value, then we
+         * could interpose a hash to hold per-subname values:
+         * old => { "fid:line" =>           [ count, incl_time, "sub1"  
]          }
+         * new => { "fid:line" => { "sub1"=>[ count, incl_time  
], "sub2"=>[...] } }
+         */
+
+        if (!SvROK(sv_tmp)) { /* autoviv hash ref - is first call of this  
subname from anywhere */
+            HV *hv = newHV();
+            sv_setsv(sv_tmp, newRV_noinc((SV *)hv));
+
+            if (1) { /* is_xs */
+                /* create dummy item with fid=0 & line=0 to act as flag to  
indicate xs */
+                AV *av = new_sub_call_info_av(aTHX);
+                av_store(av, NYTP_SCi_CALL_COUNT, newSVuv(0));
+                sv_setsv(*hv_fetch(hv, "0:0", 3, 1), newRV_noinc((SV  
*)av));
+
+                SV *sv = *hv_fetch(GvHV(PL_DBsub), subname_pv,  
(I32)SvCUR(subname_sv), 1);
+                sv_setpv(sv, ":0-0"); /* empty file name */
+                if (trace_level >= 2)
+                    warn("Adding fake DBsub entry for '%s' sysop\n",  
subname_pv);
+            }
+        }
+
+        /* drill-down to array of sub call information for this  
fid_line_key */
+        sv_tmp = *hv_fetch((HV*)SvRV(sv_tmp), fid_line_key,  
fid_line_key_len, 1);
+        if (!SvROK(sv_tmp)) {                     /* autoviv array ref */
+            AV *av = new_sub_call_info_av(aTHX);
+
+            sv_setsv(sv_tmp, newRV_noinc((SV *)av));
+            sysop_call_start.sub_av = av;
+
+            if (stash_name) /* note that a sub in this package was called  
*/
+                (void)hv_fetch(pkg_fids_hv, stash_name,  
(I32)strlen(stash_name), 1);
+        }
+        else {
+            sysop_call_start.sub_av = (AV *)SvRV(sv_tmp);
+            sv_inc(AvARRAY(sysop_call_start.sub_av)[0]); /* ++call count */
+        }
+
+        if (trace_level >= 2)
+            fprintf(stderr, " ->%s %s from %d:%d (d%d, oh %gt, sub %gs)\n",
+                "sysop", subname_pv, fid, line,
+                sysop_call_start.call_depth,
+                sysop_call_start.current_overhead_ticks,
+                sysop_call_start.current_subr_secs
+            );
+
+        sysop_call_start.call_depth = 1; /* dummy */
+        sysop_call_start.subname_sv = subname_sv;
+        strcpy(sysop_call_start.fid_line, fid_line_key);
+        /* acculumate now time we've just spent in the sysop */
+        incr_sub_inclusive_time(aTHX_ &sysop_call_start);
+
+        SETERRNO(saved_errno, 0);
+    }
+
+    return next_op;
+}
+
+
  static int
  enable_profile(pTHX_ char *file)
  {
@@ -2599,6 +2717,33 @@
              PL_ppaddr[OP_EXIT]       = pp_exit_profiler;
              PL_ppaddr[OP_EXEC]       = pp_exit_profiler;
          }
+    }
+
+    if (profile_sysops) {
+        /* possible list of sys ops to profile:
+            sysopen open close readline rcatline getc read
+            print prtf sysread syswrite send recv
+            eof tell seek sysseek readdir telldir seekdir rewinddir
+            crypt dbmopen dbmclose
+            stat lstat readlink link unlink rename symlink truncate
+            sselect select pipe_op bind connect listen accept shutdown
+            ftatime ftblk ftchr ftctime ftdir fteexec fteowned fteread
+            ftewrite ftfile ftis ftlink ftmtime ftpipe ftrexec ftrowned
+            ftrread ftsgid ftsize ftsock ftsuid fttty ftzero ftrwrite  
ftsvtx
+            fttext ftbinary custom
+            ghbyname ghbyaddr ghostent shostent ehostent      -- hosts
+            gnbyname gnbyaddr gnetent snetent enetent         -- networks
+            gpbyname gpbynumber gprotoent sprotoent eprotoent -- protocols
+            gsbyname gsbyport gservent sservent eservent      -- services
+            gpwnam gpwuid gpwent spwent epwent getlogin       -- users
+            ggrnam ggrgid ggrent sgrent egrent                -- groups
+            open_dir closedir mkdir rmdir utime chmod chown fcntl
+            backtick system fork wait waitpid glob
+            msgget msgrcv msgsnd semget semop
+            chdir flock ioctl sleep syscall dump chroot
+            Perhaps make configurable. Could interate with Opcode module.
+        */
+        PL_ppaddr[OP_SLEEP] = pp_sysop_profiler;
      }

      /* redirect opcodes for caller tracking */

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