In The Grand Trek, Filter::Util::Call's call.t didn't trek far enough.
[p5sagit/p5-mst-13.2.git] / ext / Devel / DProf / DProf.xs
index c840b24..4eef0bc 100644 (file)
@@ -24,7 +24,9 @@ db_get_cv(pTHX_ SV *sv)
            cv = INT2PTR(CV*,SvIVX(sv));
        } else {
            if (SvPOK(sv)) {
-               cv = get_cv(SvPVX(sv), TRUE);
+               STRLEN len;
+               const char *const name = SvPV(sv, len);
+               cv = get_cvn_flags(name, len, GV_ADD | SvUTF8(sv));
            } else if (SvROK(sv)) {
                cv = (CV*)SvRV(sv);
            } else {
@@ -38,8 +40,8 @@ db_get_cv(pTHX_ SV *sv)
 #  define DBG_SUB_NOTIFY(A) dprof_dbg_sub_notify(aTHX_ A)
 void
 dprof_dbg_sub_notify(pTHX_ SV *Sub) {
-    CV   *cv = db_get_cv(aTHX_ Sub);
-    GV   *gv = cv ? CvGV(cv) : NULL;
+    CV * const cv = db_get_cv(aTHX_ Sub);
+    GV * const gv = cv ? CvGV(cv) : NULL;
     if (cv && gv) {
        warn("XS DBsub(%s::%s)\n",
             ((GvSTASH(gv) && HvNAME_get(GvSTASH(gv))) ?
@@ -67,25 +69,34 @@ dprof_dbg_sub_notify(pTHX_ SV *Sub) {
 #  include <starlet.h>  /* prototype for sys$gettim() */
 #  include <lib$routines.h>
 #  define Times(ptr) (dprof_times(aTHX_ ptr))
+#  define NEEDS_DPROF_TIMES
 #else
-#  ifndef HZ
-#    ifdef CLK_TCK
-#      define HZ ((I32)CLK_TCK)
-#    else
-#      define HZ 60
-#    endif
-#  endif
-#  ifdef OS2                           /* times() has significant overhead */
+#  ifdef BSDish
 #    define Times(ptr) (dprof_times(aTHX_ ptr))
-#    define INCL_DOSPROFILE
-#    define INCL_DOSERRORS
-#    include <os2.h>
-#    define toLongLong(arg) (*(long long*)&(arg))
-#    define DPROF_HZ g_dprof_ticks
-#  else
-#    define Times(ptr) (times(ptr))
+#    define NEEDS_DPROF_TIMES
+#    define HZ 1000000
 #    define DPROF_HZ HZ
-#  endif 
+#  else
+#    ifndef HZ
+#      ifdef CLK_TCK
+#        define HZ ((I32)CLK_TCK)
+#      else
+#        define HZ 60
+#      endif
+#    endif
+#    ifdef OS2                         /* times() has significant overhead */
+#      define Times(ptr) (dprof_times(aTHX_ ptr))
+#      define NEEDS_DPROF_TIMES
+#      define INCL_DOSPROFILE
+#      define INCL_DOSERRORS
+#      include <os2.h>
+#      define toLongLong(arg) (*(long long*)&(arg))
+#      define DPROF_HZ g_dprof_ticks
+#    else
+#      define Times(ptr) (times(ptr))
+#      define DPROF_HZ HZ
+#    endif 
+#  endif
 #endif
 
 XS(XS_Devel__DProf_END);        /* used by prof_mark() */
@@ -98,7 +109,7 @@ union prof_any {
         clock_t tms_utime;  /* cpu time spent in user space */
         clock_t tms_stime;  /* cpu time spent in system */
         clock_t realtime;   /* elapsed real time, in ticks */
-        char *name;
+        const char *name;
         U32 id;
         opcode ptype;
 };
@@ -107,7 +118,7 @@ typedef union prof_any PROFANY;
 
 typedef struct {
     U32                dprof_ticks;
-    char*      out_file_name;  /* output file (defaults to tmon.out) */
+    const char*        out_file_name;  /* output file (defaults to tmon.out) */
     PerlIO*    fp;             /* pointer to tmon.out file */
     Off_t      TIMES_LOCATION; /* Where in the file to store the time totals */
     int                SAVE_STACK;     /* How much data to buffer until end of run */
@@ -136,9 +147,7 @@ typedef struct {
     long long  start_cnt;
 #endif
 #ifdef PERL_IMPLICIT_CONTEXT
-#  define register
-    pTHX;
-#  undef register
+    PerlInterpreter *my_perl;
 #endif
 } prof_state_t;
 
@@ -170,34 +179,34 @@ prof_state_t g_prof_state;
 #define g_default_perldb       g_prof_state.default_perldb
 #define g_depth                        g_prof_state.depth
 #ifdef PERL_IMPLICIT_CONTEXT
-#  define g_THX                        g_prof_state.aTHX
+#  define g_THX                        g_prof_state.my_perl
 #endif
 #ifdef OS2
 #  define g_frequ              g_prof_state.frequ
 #  define g_start_cnt          g_prof_state.start_cnt
 #endif
 
-clock_t
+#ifdef NEEDS_DPROF_TIMES
+static clock_t
 dprof_times(pTHX_ struct tms *t)
 {
 #ifdef OS2
     ULONG rc;
     QWORD cnt;
-    STRLEN n_a;
     
     if (!g_frequ) {
        if (CheckOSError(DosTmrQueryFreq(&g_frequ)))
-           croak("DosTmrQueryFreq: %s", SvPV(perl_get_sv("!",TRUE),n_a));
+           croak("DosTmrQueryFreq: %s", SvPV_nolen(perl_get_sv("!",GV_ADD)));
        else
            g_frequ = g_frequ/DPROF_HZ; /* count per tick */
        if (CheckOSError(DosTmrQueryTime(&cnt)))
            croak("DosTmrQueryTime: %s",
-                 SvPV(perl_get_sv("!",TRUE), n_a));
+                 SvPV_nolen_const(perl_get_sv("!",GV_ADD)));
        g_start_cnt = toLongLong(cnt);
     }
 
     if (CheckOSError(DosTmrQueryTime(&cnt)))
-           croak("DosTmrQueryTime: %s", SvPV(perl_get_sv("!",TRUE), n_a));
+           croak("DosTmrQueryTime: %s", SvPV_nolen(perl_get_sv("!",GV_ADD)));
     t->tms_stime = 0;
     return (t->tms_utime = (toLongLong(cnt) - g_start_cnt)/g_frequ);
 #else          /* !OS2 */
@@ -224,10 +233,37 @@ dprof_times(pTHX_ struct tms *t)
     times((tbuffer_t *)t);
     return (clock_t) retval;
 #  else                /* !VMS && !OS2 */
+#    ifdef BSDish
+#      include <sys/resource.h>
+    struct rusage ru;
+    struct timeval tv;
+    /* Measure offset from start time to avoid overflow  */
+    static struct timeval tv0 = { 0, 0 };
+
+    if (!tv0.tv_sec)
+        if (gettimeofday(&tv0, NULL) < 0)
+            croak("gettimeofday: %s", SvPV_nolen_const(perl_get_sv("!",GV_ADD)));
+    
+    if (getrusage(0, &ru) < 0)
+        croak("getrusage: %s", SvPV_nolen_const(perl_get_sv("!",GV_ADD)));
+
+    if (gettimeofday(&tv, NULL) < 0)
+        croak("gettimeofday: %s", SvPV_nolen_const(perl_get_sv("!",GV_ADD)));
+
+    t->tms_stime = DPROF_HZ * ru.ru_stime.tv_sec + ru.ru_stime.tv_usec;
+    t->tms_utime = DPROF_HZ * ru.ru_utime.tv_sec + ru.ru_utime.tv_usec;
+
+    if (tv.tv_usec < tv0.tv_usec)
+        tv.tv_sec--, tv.tv_usec += DPROF_HZ;
+
+    return DPROF_HZ * (tv.tv_sec - tv0.tv_sec) + tv.tv_usec - tv0.tv_usec;
+#    else  /* !VMS && !OS2 && !BSD! */
     return times(t);
+#    endif
 #  endif
 #endif
 }
+#endif
 
 static void
 prof_dumpa(pTHX_ opcode ptype, U32 id)
@@ -250,7 +286,7 @@ prof_dumpa(pTHX_ opcode ptype, U32 id)
 }   
 
 static void
-prof_dumps(pTHX_ U32 id, char *pname, char *gname)
+prof_dumps(pTHX_ U32 id, const char *pname, const char *gname)
 {
     PerlIO_printf(g_fp,"& %"UVxf" %s %s\n", (UV)id, pname, gname);
 }   
@@ -266,28 +302,28 @@ prof_dump_until(pTHX_ long ix)
 {
     long base = 0;
     struct tms t1, t2;
-    clock_t realtime1, realtime2;
+    clock_t realtime2;
 
-    realtime1 = Times(&t1);
+    const clock_t realtime1 = Times(&t1);
 
     while (base < ix) {
-       opcode ptype = g_profstack[base++].ptype;
+       const opcode ptype = g_profstack[base++].ptype;
        if (ptype == OP_TIME) {
-           long tms_utime = g_profstack[base++].tms_utime;
-           long tms_stime = g_profstack[base++].tms_stime;
-           long realtime = g_profstack[base++].realtime;
+           const long tms_utime = g_profstack[base++].tms_utime;
+           const long tms_stime = g_profstack[base++].tms_stime;
+           const long realtime = g_profstack[base++].realtime;
 
            prof_dumpt(aTHX_ tms_utime, tms_stime, realtime);
        }
        else if (ptype == OP_GV) {
-           U32 id = g_profstack[base++].id;
-           char *pname = g_profstack[base++].name;
-           char *gname = g_profstack[base++].name;
+           const U32 id = g_profstack[base++].id;
+           const char * const pname = g_profstack[base++].name;
+           const char * const gname = g_profstack[base++].name;
 
            prof_dumps(aTHX_ id, pname, gname);
        }
        else {
-           U32 id = g_profstack[base++].id;
+           const U32 id = g_profstack[base++].id;
            prof_dumpa(aTHX_ ptype, id);
        }
     }
@@ -316,7 +352,7 @@ prof_dump_until(pTHX_ long ix)
 }
 
 static void
-set_cv_key(pTHX_ CV *cv, char *pname, char *gname)
+set_cv_key(pTHX_ CV *cv, const char *pname, const char *gname)
 {
        SvGROW(g_key_hash, sizeof(CV**) + strlen(pname) + strlen(gname) + 3);
        sv_setpvn(g_key_hash, (char*)&cv, sizeof(CV**));
@@ -331,7 +367,7 @@ prof_mark(pTHX_ opcode ptype)
     struct tms t;
     clock_t realtime, rdelta, udelta, sdelta;
     U32 id;
-    SV *Sub = GvSV(PL_DBsub);  /* name of current sub */
+    SV * const Sub = GvSV(PL_DBsub);   /* name of current sub */
 
     if (g_SAVE_STACK) {
        if (g_profstack_ix + 10 > g_profstack_max) {
@@ -366,17 +402,19 @@ prof_mark(pTHX_ opcode ptype)
     {
        SV **svp;
        char *gname, *pname;
-       CV *cv;
-       GV *gv;
 
-       cv = db_get_cv(aTHX_ Sub);
-       gv = CvGV(cv);
-       pname = GvSTASH(gv) ? HvNAME_get(GvSTASH(gv)) : 0;
-       pname = pname ? pname : (char *) "(null)";
-       gname = GvNAME(gv);
+       CV * const cv = db_get_cv(aTHX_ Sub);
+       GV * const gv = CvGV(cv);
+       if (isGV_with_GP(gv)) {
+           pname = GvSTASH(gv) ? HvNAME_get(GvSTASH(gv)) : NULL;
+           pname = pname ? pname : (char *) "(null)";
+           gname = GvNAME(gv);
+       } else {
+           gname = pname = (char *) "(null)";
+       }
 
        set_cv_key(aTHX_ cv, pname, gname);
-       svp = hv_fetch(g_cv_hash, SvPVX(g_key_hash), SvCUR(g_key_hash), TRUE);
+       svp = hv_fetch(g_cv_hash, SvPVX_const(g_key_hash), SvCUR(g_key_hash), TRUE);
        if (!SvOK(*svp)) {
            sv_setiv(*svp, id = ++g_lastid);
            if (CvXSUB(cv) == XS_Devel__DProf_END)
@@ -430,33 +468,30 @@ prof_mark(pTHX_ opcode ptype)
     }
 }
 
-#ifdef PL_NEEDED
-#  define defstash PL_defstash
-#endif
-
 /* Counts overhead of prof_mark and extra XS call. */
 static void
 test_time(pTHX_ clock_t *r, clock_t *u, clock_t *s)
 {
-    CV *cv = perl_get_cv("Devel::DProf::NONESUCH_noxs", FALSE);
-    int i, j, k = 0;
-    HV *oldstash = PL_curstash;
+    CV * const cv = get_cvs("Devel::DProf::NONESUCH_noxs", 0);
+    HV * const oldstash = PL_curstash;
     struct tms t1, t2;
-    clock_t realtime1 = 0, realtime2 = 0;
-    U32 ototal = g_total;
-    U32 ostack = g_SAVE_STACK;
-    U32 operldb = PL_perldb;
+    const U32 ototal = g_total;
+    const U32 ostack = g_SAVE_STACK;
+    const U32 operldb = PL_perldb;
+    int k = 0;
+
+    clock_t realtime1 = Times(&t1);
+    clock_t realtime2 = 0;
 
     g_SAVE_STACK = 1000000;
-    realtime1 = Times(&t1);
-    
+
     while (k < 2) {
-       i = 0;
+       int i = 0;
            /* Disable debugging of perl_call_sv on second pass: */
        PL_curstash = (k == 0 ? PL_defstash : PL_debstash);
        PL_perldb = g_default_perldb;
        while (++i <= 100) {
-           j = 0;
+           int j = 0;
            g_profstack_ix = 0;         /* Do not let the stack grow */
            while (++j <= 100) {
 /*             prof_mark(aTHX_ OP_ENTERSUB); */
@@ -549,7 +584,7 @@ prof_record(pTHX)
 static void
 check_depth(pTHX_ void *foo)
 {
-    U32 need_depth = PTR2UV(foo);
+    const U32 need_depth = PTR2UV(foo);
     if (need_depth != g_depth) {
        if (need_depth > g_depth) {
            warn("garbled call depth when profiling");
@@ -569,11 +604,12 @@ check_depth(pTHX_ void *foo)
 #define for_real
 #ifdef for_real
 
+XS(XS_DB_sub);
 XS(XS_DB_sub)
 {
     dMARK;
     dORIGMARK;
-    SV *Sub = GvSV(PL_DBsub);          /* name of current sub */
+    SV * const Sub = GvSV(PL_DBsub);           /* name of current sub */
 
 #ifdef PERL_IMPLICIT_CONTEXT
     /* profile only the interpreter that loaded us */
@@ -584,9 +620,9 @@ XS(XS_DB_sub)
     else
 #endif
     {
-       HV *oldstash = PL_curstash;
-       I32 old_scopestack_ix = PL_scopestack_ix;
-       I32 old_cxstack_ix = cxstack_ix;
+       HV * const oldstash = PL_curstash;
+       const I32 old_scopestack_ix = PL_scopestack_ix;
+       const I32 old_cxstack_ix = cxstack_ix;
 
         DBG_SUB_NOTIFY(Sub);
 
@@ -611,6 +647,7 @@ XS(XS_DB_sub)
     return;
 }
 
+XS(XS_DB_goto);
 XS(XS_DB_goto)
 {
 #ifdef PERL_IMPLICIT_CONTEXT
@@ -633,8 +670,8 @@ XS(XS_DB_goto)
        PPCODE:
            {
                 dORIGMARK;
-                HV *oldstash = PL_curstash;
-               SV *Sub = GvSV(PL_DBsub);       /* name of current sub */
+               HV * const oldstash = PL_curstash;
+               SV * const Sub = GvSV(PL_DBsub);        /* name of current sub */
                 /* SP -= items;  added by xsubpp */
                 DBG_SUB_NOTIFY(Sub);
 
@@ -700,7 +737,7 @@ BOOT:
          * while we do this.
          */
         {
-           bool warn_tmp = PL_dowarn;
+           const bool warn_tmp = PL_dowarn;
            PL_dowarn = 0;
            newXS("DB::sub", XS_DB_sub, file);
            newXS("DB::goto", XS_DB_goto, file);
@@ -710,7 +747,7 @@ BOOT:
         sv_setiv(PL_DBsingle, 0);      /* disable DB single-stepping */
 
        {
-           char *buffer = getenv("PERL_DPROF_BUFFER");
+           const char *buffer = getenv("PERL_DPROF_BUFFER");
 
            if (buffer) {
                g_SAVE_STACK = atoi(buffer);
@@ -738,7 +775,7 @@ BOOT:
        g_key_hash = newSV(256);
         g_prof_pid = (int)getpid();
 
-       New(0, g_profstack, g_profstack_max, PROFANY);
+       Newx(g_profstack, g_profstack_max, PROFANY);
         prof_recordheader(aTHX);
         DBG_TIMER_NOTIFY("Profiler timer is on.\n");
        g_orealtime = g_rprof_start = Times(&g_prof_start);