📄 dprof.xs
字号:
#define PERL_NO_GET_CONTEXT#include "EXTERN.h"#include "perl.h"#include "XSUB.h"/*#define DBG_SUB 1 *//*#define DBG_TIMER 1 */#ifdef DBG_SUB# define DBG_SUB_NOTIFY(A,B) warn(A, B)#else# define DBG_SUB_NOTIFY(A,B) /* nothing */#endif#ifdef DBG_TIMER# define DBG_TIMER_NOTIFY(A) warn(A)#else# define DBG_TIMER_NOTIFY(A) /* nothing */#endif/* HZ == clock ticks per second */#ifdef VMS# define HZ ((I32)CLK_TCK)# define DPROF_HZ HZ# include <starlet.h> /* prototype for sys$gettim() */# include <lib$routines.h># define Times(ptr) (dprof_times(aTHX_ ptr))#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 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 #endifXS(XS_Devel__DProf_END); /* used by prof_mark() *//* Everything is built on times(2). See its manpage for a description * of the timings. */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; U32 id; opcode ptype;};typedef union prof_any PROFANY;typedef struct { U32 dprof_ticks; char* out_file_name; /* output file (defaults to tmon.out) */ PerlIO* fp; /* pointer to tmon.out file */ long TIMES_LOCATION; /* Where in the file to store the time totals */ int SAVE_STACK; /* How much data to buffer until end of run */ int prof_pid; /* pid of profiled process */ struct tms prof_start; struct tms prof_end; clock_t rprof_start; /* elapsed real time ticks */ clock_t rprof_end; clock_t wprof_u; clock_t wprof_s; clock_t wprof_r; clock_t otms_utime; clock_t otms_stime; clock_t orealtime; PROFANY* profstack; int profstack_max; int profstack_ix; HV* cv_hash; U32 total; U32 lastid; U32 default_perldb; U32 depth;#ifdef OS2 ULONG frequ; long long start_cnt;#endif#ifdef PERL_IMPLICIT_CONTEXT# define register pTHX;# undef register#endif} prof_state_t;prof_state_t g_prof_state;#define g_dprof_ticks g_prof_state.dprof_ticks#define g_out_file_name g_prof_state.out_file_name#define g_fp g_prof_state.fp#define g_TIMES_LOCATION g_prof_state.TIMES_LOCATION#define g_SAVE_STACK g_prof_state.SAVE_STACK#define g_prof_pid g_prof_state.prof_pid#define g_prof_start g_prof_state.prof_start#define g_prof_end g_prof_state.prof_end#define g_rprof_start g_prof_state.rprof_start#define g_rprof_end g_prof_state.rprof_end#define g_wprof_u g_prof_state.wprof_u#define g_wprof_s g_prof_state.wprof_s#define g_wprof_r g_prof_state.wprof_r#define g_otms_utime g_prof_state.otms_utime#define g_otms_stime g_prof_state.otms_stime#define g_orealtime g_prof_state.orealtime#define g_profstack g_prof_state.profstack#define g_profstack_max g_prof_state.profstack_max#define g_profstack_ix g_prof_state.profstack_ix#define g_cv_hash g_prof_state.cv_hash#define g_total g_prof_state.total#define g_lastid g_prof_state.lastid#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#endif#ifdef OS2# define g_frequ g_prof_state.frequ# define g_start_cnt g_prof_state.start_cnt#endifclock_tdprof_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)); else g_frequ = g_frequ/DPROF_HZ; /* count per tick */ if (CheckOSError(DosTmrQueryTime(&cnt))) croak("DosTmrQueryTime: %s", SvPV(perl_get_sv("!",TRUE), n_a)); g_start_cnt = toLongLong(cnt); } if (CheckOSError(DosTmrQueryTime(&cnt))) croak("DosTmrQueryTime: %s", SvPV(perl_get_sv("!",TRUE), n_a)); t->tms_stime = 0; return (t->tms_utime = (toLongLong(cnt) - g_start_cnt)/g_frequ);#else /* !OS2 */# ifdef VMS clock_t retval; /* Get wall time and convert to 10 ms intervals to * produce the return value dprof expects */# if defined(__DECC) && defined (__ALPHA)# include <ints.h> uint64 vmstime; _ckvmssts(sys$gettim(&vmstime)); vmstime /= 100000; retval = vmstime & 0x7fffffff;# else /* (Older hw or ccs don't have an atomic 64-bit type, so we * juggle 32-bit ints (and a float) to produce a time_t result * with minimal loss of information.) */ long int vmstime[2],remainder,divisor = 100000; _ckvmssts(sys$gettim((unsigned long int *)vmstime)); vmstime[1] &= 0x7fff; /* prevent overflow in EDIV */ _ckvmssts(lib$ediv(&divisor,vmstime,(long int *)&retval,&remainder));# endif /* Fill in the struct tms using the CRTL routine . . .*/ times((tbuffer_t *)t); return (clock_t) retval;# else /* !VMS && !OS2 */ return times(t);# endif#endif}static voidprof_dumpa(pTHX_ opcode ptype, U32 id){ if (ptype == OP_LEAVESUB) { PerlIO_printf(g_fp,"- %"UVxf"\n", (UV)id); } else if(ptype == OP_ENTERSUB) { PerlIO_printf(g_fp,"+ %"UVxf"\n", (UV)id); } else if(ptype == OP_GOTO) { PerlIO_printf(g_fp,"* %"UVxf"\n", (UV)id); } else if(ptype == OP_DIE) { PerlIO_printf(g_fp,"/ %"UVxf"\n", (UV)id); } else { PerlIO_printf(g_fp,"Profiler unknown prof code %d\n", ptype); }} static voidprof_dumps(pTHX_ U32 id, char *pname, char *gname){ PerlIO_printf(g_fp,"& %"UVxf" %s %s\n", (UV)id, pname, gname);} static voidprof_dumpt(pTHX_ long tms_utime, long tms_stime, long realtime){ PerlIO_printf(g_fp,"@ %ld %ld %ld\n", tms_utime, tms_stime, realtime);} static voidprof_dump_until(pTHX_ long ix){ long base = 0; struct tms t1, t2; clock_t realtime1, realtime2; realtime1 = Times(&t1); while (base < ix) { 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; 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; prof_dumps(aTHX_ id, pname, gname); } else { U32 id = g_profstack[base++].id; prof_dumpa(aTHX_ ptype, id); } } PerlIO_flush(g_fp); realtime2 = Times(&t2); if (realtime2 != realtime1 || t1.tms_utime != t2.tms_utime || t1.tms_stime != t2.tms_stime) { g_wprof_r += realtime2 - realtime1; g_wprof_u += t2.tms_utime - t1.tms_utime; g_wprof_s += t2.tms_stime - t1.tms_stime; PerlIO_printf(g_fp,"+ & Devel::DProf::write\n"); PerlIO_printf(g_fp,"@ %"IVdf" %"IVdf" %"IVdf"\n", /* The (IV) casts are one possibility: * the Painfully Correct Way would be to * have Clock_t_f. */ (IV)(t2.tms_utime - t1.tms_utime), (IV)(t2.tms_stime - t1.tms_stime), (IV)(realtime2 - realtime1)); PerlIO_printf(g_fp,"- & Devel::DProf::write\n"); g_otms_utime = t2.tms_utime; g_otms_stime = t2.tms_stime; g_orealtime = realtime2; PerlIO_flush(g_fp); }}static voidprof_mark(pTHX_ opcode ptype){ struct tms t; clock_t realtime, rdelta, udelta, sdelta; U32 id; SV *Sub = GvSV(PL_DBsub); /* name of current sub */ if (g_SAVE_STACK) { if (g_profstack_ix + 5 > g_profstack_max) { g_profstack_max = g_profstack_max * 3 / 2; Renew(g_profstack, g_profstack_max, PROFANY); } } realtime = Times(&t); rdelta = realtime - g_orealtime; udelta = t.tms_utime - g_otms_utime; sdelta = t.tms_stime - g_otms_stime; if (rdelta || udelta || sdelta) { if (g_SAVE_STACK) { g_profstack[g_profstack_ix++].ptype = OP_TIME; g_profstack[g_profstack_ix++].tms_utime = udelta; g_profstack[g_profstack_ix++].tms_stime = sdelta; g_profstack[g_profstack_ix++].realtime = rdelta; } else { /* Write it to disk now so's not to eat up core */ if (g_prof_pid == (int)getpid()) { prof_dumpt(aTHX_ udelta, sdelta, rdelta); PerlIO_flush(g_fp); } } g_orealtime = realtime; g_otms_stime = t.tms_stime; g_otms_utime = t.tms_utime; } { SV **svp; char *gname, *pname; CV *cv; cv = INT2PTR(CV*,SvIVX(Sub)); svp = hv_fetch(g_cv_hash, (char*)&cv, sizeof(CV*), TRUE); if (!SvOK(*svp)) { GV *gv = CvGV(cv); sv_setiv(*svp, id = ++g_lastid); pname = ((GvSTASH(gv) && HvNAME(GvSTASH(gv))) ? HvNAME(GvSTASH(gv)) : "(null)"); gname = GvNAME(gv); if (CvXSUB(cv) == XS_Devel__DProf_END) return; if (g_SAVE_STACK) { /* Store it for later recording -JH */ g_profstack[g_profstack_ix++].ptype = OP_GV; g_profstack[g_profstack_ix++].id = id; g_profstack[g_profstack_ix++].name = pname; g_profstack[g_profstack_ix++].name = gname; } else { /* Write it to disk now so's not to eat up core */ /* Only record the parent's info */ if (g_prof_pid == (int)getpid()) { prof_dumps(aTHX_ id, pname, gname); PerlIO_flush(g_fp); } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -