This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
First steps of making builds outside the source
[perl5.git] / ext / Devel / DProf / DProf.xs
1 /* XXX DProf could use some cleanups for PERL_IMPLICIT_CONTEXT */
2
3 #define PERL_POLLUTE
4
5 #include "EXTERN.h"
6 #include "perl.h"
7 #include "XSUB.h"
8
9 /* For older Perls */
10 #ifndef dTHR
11 #  define dTHR int dummy_thr
12 #endif  /* dTHR */ 
13
14 /*#define DBG_SUB 1     /* */
15 /*#define DBG_TIMER 1   /* */
16
17 #ifdef DBG_SUB
18 #  define DBG_SUB_NOTIFY(A,B) warn( A, B )
19 #else
20 #  define DBG_SUB_NOTIFY(A,B)  /* nothing */
21 #endif
22
23 #ifdef DBG_TIMER
24 #  define DBG_TIMER_NOTIFY(A) warn( A )
25 #else
26 #  define DBG_TIMER_NOTIFY(A)  /* nothing */
27 #endif
28
29 static U32 dprof_ticks;
30
31 /* HZ == clock ticks per second */
32 #ifdef VMS
33 #  define HZ CLK_TCK
34 #  define DPROF_HZ HZ
35 #  include <starlet.h>  /* prototype for sys$gettim() */
36    clock_t dprof_times(struct tms *bufptr) {
37         clock_t retval;
38         /* Get wall time and convert to 10 ms intervals to
39          * produce the return value dprof expects */
40 #  if defined(__DECC) && defined (__ALPHA)
41 #    include <ints.h>
42         uint64 vmstime;
43         _ckvmssts(sys$gettim(&vmstime));
44         vmstime /= 100000;
45         retval = vmstime & 0x7fffffff;
46 #  else
47         /* (Older hw or ccs don't have an atomic 64-bit type, so we
48          * juggle 32-bit ints (and a float) to produce a time_t result
49          * with minimal loss of information.) */
50         long int vmstime[2],remainder,divisor = 100000;
51         _ckvmssts(sys$gettim((unsigned long int *)vmstime));
52         vmstime[1] &= 0x7fff;  /* prevent overflow in EDIV */
53         _ckvmssts(lib$ediv(&divisor,vmstime,(long int *)&retval,&remainder));
54 #  endif
55         /* Fill in the struct tms using the CRTL routine . . .*/
56         times((tbuffer_t *)bufptr);
57         return (clock_t) retval;
58    }
59 #  define Times(ptr) (dprof_times(ptr))
60 #else
61 #  ifndef HZ
62 #    ifdef CLK_TCK
63 #      define HZ CLK_TCK
64 #    else
65 #      define HZ 60
66 #    endif
67 #  endif
68 #  ifdef OS2                            /* times() has significant overhead */
69 #    define Times(ptr) (dprof_times(ptr))
70 #    define INCL_DOSPROFILE
71 #    define INCL_DOSERRORS
72 #    include <os2.h>
73 #    define toLongLong(arg) (*(long long*)&(arg))
74 #    define DPROF_HZ dprof_ticks
75
76 static ULONG frequ;
77 static long long start_cnt;
78 clock_t
79 dprof_times(struct tms *t)
80 {
81     ULONG rc;
82     QWORD cnt;
83     
84     if (!frequ) {
85         if (CheckOSError(DosTmrQueryFreq(&frequ)))
86             croak("DosTmrQueryFreq: %s", SvPV(perl_get_sv("!",TRUE),na));
87         else
88             frequ = frequ/DPROF_HZ;     /* count per tick */
89         if (CheckOSError(DosTmrQueryTime(&cnt)))
90             croak("DosTmrQueryTime: %s",
91                   SvPV(perl_get_sv("!",TRUE),na));
92         start_cnt = toLongLong(cnt);
93     }
94
95     if (CheckOSError(DosTmrQueryTime(&cnt)))
96             croak("DosTmrQueryTime: %s", SvPV(perl_get_sv("!",TRUE),na));
97     t->tms_stime = 0;
98     return (t->tms_utime = (toLongLong(cnt) - start_cnt)/frequ);
99 }
100 #  else
101 #    define Times(ptr) (times(ptr))
102 #    define DPROF_HZ HZ
103 #  endif 
104 #endif
105
106 XS(XS_Devel__DProf_END);        /* used by prof_mark() */
107
108 static SV * Sub;        /* pointer to $DB::sub */
109 static PerlIO *fp;      /* pointer to tmon.out file */
110
111 /* Added -JH */
112 static long TIMES_LOCATION=42;/* Where in the file to store the time totals */
113 static int SAVE_STACK = 1<<14;          /* How much data to buffer until */
114                                         /* end of run */
115
116 static int prof_pid;    /* pid of profiled process */
117
118 /* Everything is built on times(2).  See its manpage for a description
119  * of the timings.
120  */
121
122 static
123 struct tms      prof_start,
124                 prof_end;
125
126 static
127 clock_t         rprof_start, /* elapsed real time, in ticks */
128                 rprof_end,
129                 wprof_u, wprof_s, wprof_r;
130
131 union prof_any {
132         clock_t tms_utime;  /* cpu time spent in user space */
133         clock_t tms_stime;  /* cpu time spent in system */
134         clock_t realtime;   /* elapsed real time, in ticks */
135         char *name;
136         U32 id;
137         opcode ptype;
138 };
139
140 typedef union prof_any PROFANY;
141
142 static PROFANY  *profstack;
143 static int      profstack_max = 128;
144 static int      profstack_ix = 0;
145
146 static void
147 prof_dump(opcode ptype, char *name)
148 {
149     if(ptype == OP_LEAVESUB){
150         PerlIO_printf(fp,"- & %s\n", name );
151     } else if(ptype == OP_ENTERSUB) {
152         PerlIO_printf(fp,"+ & %s\n", name );
153     } else if(ptype == OP_DIE) {
154         PerlIO_printf(fp,"/ & %s\n", name );
155     } else {
156         PerlIO_printf(fp,"Profiler unknown prof code %d\n", ptype);
157     }
158     safefree(name);
159 }   
160
161 static void
162 prof_dumpa(opcode ptype, U32 id)
163 {
164     if(ptype == OP_LEAVESUB){
165         PerlIO_printf(fp,"- %lx\n", id );
166     } else if(ptype == OP_ENTERSUB) {
167         PerlIO_printf(fp,"+ %lx\n", id );
168     } else if(ptype == OP_GOTO) {
169         PerlIO_printf(fp,"* %lx\n", id );
170     } else if(ptype == OP_DIE) {
171         PerlIO_printf(fp,"/ %lx\n", id );
172     } else {
173         PerlIO_printf(fp,"Profiler unknown prof code %d\n", ptype);
174     }
175 }   
176
177 static void
178 prof_dumps(U32 id, char *pname, char *gname)
179 {
180     PerlIO_printf(fp,"& %lx %s %s\n", id, pname, gname);
181 }   
182
183 static clock_t otms_utime, otms_stime, orealtime;
184
185 static void
186 prof_dumpt(long tms_utime, long tms_stime, long realtime)
187 {
188     PerlIO_printf(fp,"@ %ld %ld %ld\n", tms_utime, tms_stime, realtime);
189 }   
190
191 static void
192 prof_dump_until(long ix)
193 {
194     long base = 0;
195     struct tms t1, t2;
196     clock_t realtime1, realtime2;
197
198     realtime1 = Times(&t1);
199
200     while( base < ix ){
201         opcode ptype = profstack[base++].ptype;
202         if (ptype == OP_TIME) {
203             long tms_utime = profstack[base++].tms_utime;
204             long tms_stime = profstack[base++].tms_stime;
205             long realtime = profstack[base++].realtime;
206
207             prof_dumpt(tms_utime, tms_stime, realtime);
208         } else if (ptype == OP_GV) {
209             U32 id = profstack[base++].id;
210             char *pname = profstack[base++].name;
211             char *gname = profstack[base++].name;
212
213             prof_dumps(id, pname, gname);
214         } else {
215 #ifdef PERLDBf_NONAME
216             U32 id = profstack[base++].id;
217             prof_dumpa(ptype, id);
218 #else
219             char *name = profstack[base++].name;
220             prof_dump(ptype, name);
221 #endif 
222         }
223     }
224     PerlIO_flush(fp);
225     realtime2 = Times(&t2);
226     if (realtime2 != realtime1 || t1.tms_utime != t2.tms_utime
227         || t1.tms_stime != t2.tms_stime) {
228         wprof_r += realtime2 - realtime1;
229         wprof_u += t2.tms_utime - t1.tms_utime;
230         wprof_s += t2.tms_stime - t1.tms_stime;
231
232         PerlIO_printf(fp,"+ & Devel::DProf::write\n" );
233         PerlIO_printf(fp,"@ %ld %ld %ld\n", 
234                 t2.tms_utime - t1.tms_utime, t2.tms_stime - t1.tms_stime, 
235                 realtime2 - realtime1);
236         PerlIO_printf(fp,"- & Devel::DProf::write\n" );
237         otms_utime = t2.tms_utime;
238         otms_stime = t2.tms_stime;
239         orealtime = realtime2;
240         PerlIO_flush(fp);
241     }
242 }
243
244 static HV* cv_hash;
245 static U32 total = 0;
246
247 static void
248 prof_mark( opcode ptype )
249 {
250         struct tms t;
251         clock_t realtime, rdelta, udelta, sdelta;
252         char *name, *pv;
253         char *hvname;
254         STRLEN len;
255         SV *sv;
256         U32 id;
257
258         if( SAVE_STACK ){
259                 if( profstack_ix + 5 > profstack_max ){
260                         profstack_max = profstack_max * 3 / 2;
261                         Renew( profstack, profstack_max, PROFANY );
262                 }
263         }
264
265         realtime = Times(&t);
266         rdelta = realtime - orealtime;
267         udelta = t.tms_utime - otms_utime;
268         sdelta = t.tms_stime - otms_stime;
269         if (rdelta || udelta || sdelta) {
270             if (SAVE_STACK) {
271                 profstack[profstack_ix++].ptype = OP_TIME;
272                 profstack[profstack_ix++].tms_utime = udelta;
273                 profstack[profstack_ix++].tms_stime = sdelta;
274                 profstack[profstack_ix++].realtime = rdelta;
275             } else { /* Write it to disk now so's not to eat up core */
276                 if (prof_pid == (int)getpid()) {
277                     prof_dumpt(udelta, sdelta, rdelta);
278                     PerlIO_flush(fp);
279                 }
280             }
281             orealtime = realtime;
282             otms_stime = t.tms_stime;
283             otms_utime = t.tms_utime;
284         }
285
286 #ifdef PERLDBf_NONAME
287         {
288             SV **svp;
289             char *gname, *pname;
290             static U32 lastid;
291             CV *cv;
292
293             cv = (CV*)SvIVX(Sub);
294             svp = hv_fetch(cv_hash, (char*)&cv, sizeof(CV*), TRUE);
295             if (!SvOK(*svp)) {
296                 GV *gv = CvGV(cv);
297                     
298                 sv_setiv(*svp, id = ++lastid);
299                 pname = ((GvSTASH(gv) && HvNAME(GvSTASH(gv))) 
300                          ? HvNAME(GvSTASH(gv)) 
301                          : "(null)");
302                 gname = GvNAME(gv);
303                 if (CvXSUB(cv) == XS_Devel__DProf_END)
304                     return;
305                 if (SAVE_STACK) { /* Store it for later recording  -JH */
306                     profstack[profstack_ix++].ptype = OP_GV;
307                     profstack[profstack_ix++].id = id;
308                     profstack[profstack_ix++].name = pname;
309                     profstack[profstack_ix++].name = gname;
310                 } else { /* Write it to disk now so's not to eat up core */
311
312                     /* Only record the parent's info */
313                     if (prof_pid == (int)getpid()) {
314                         prof_dumps(id, pname, gname);
315                         PerlIO_flush(fp);
316                     } else
317                         perldb = 0;             /* Do not debug the kid. */
318                 }
319             } else {
320                 id = SvIV(*svp);
321             }
322         }
323 #else
324         pv = SvPV( Sub, len );
325
326         if( SvROK(Sub) ){
327                 /* Attempt to make CODE refs slightly identifiable by
328                  * including their package name.
329                  */
330                 sv = (SV*)SvRV(Sub);
331                 if( sv && SvTYPE(sv) == SVt_PVCV ){
332                         if( CvSTASH(sv) ){
333                                 hvname = HvNAME(CvSTASH(sv));
334                         }
335                         else if( CvXSUB(sv) == &XS_Devel__DProf_END ){
336                                 /*warn( "prof_mark() found dprof::end");*/
337                                 return; /* don't profile Devel::DProf::END */
338                         }
339                         else{
340                     croak( "DProf prof_mark() lost on CODE ref %s\n", pv );
341                         }
342                         len += strlen( hvname ) + 2;  /* +2 for ::'s */
343
344                 }
345                 else{
346         croak( "DProf prof_mark() lost on supposed CODE ref %s.\n", pv );
347                 }
348                 name = (char *)safemalloc( len * sizeof(char) + 1 );
349                 strcpy( name, hvname );
350                 strcat( name, "::" );
351                 strcat( name, pv );
352         }
353         else{
354                 if( *(pv+len-1) == 'D' ){
355                         /* It could be an &AUTOLOAD. */
356
357                         /* I measured a bunch of *.pl and *.pm (from Perl
358                          * distribution and other misc things) and found
359                          * 780 fully-qualified names.  They averaged
360                          * about 19 chars each.  Only 1 of those names
361                          * ended with 'D' and wasn't an &AUTOLOAD--it
362                          * was &overload::OVERLOAD.
363                          *    --dmr 2/19/96
364                          */
365
366                         if( strcmp( pv+len-9, ":AUTOLOAD" ) == 0 ){
367                                 /* The sub name is in $AUTOLOAD */
368                                 sv = perl_get_sv( pv, 0 );
369                                 if( sv == NULL ){
370                 croak("DProf prof_mark() lost on AUTOLOAD (%s).\n", pv );
371                                 }
372                                 pv = SvPV( sv, na );
373                                 DBG_SUB_NOTIFY( "  AUTOLOAD(%s)\n", pv );
374                         }
375                 }
376                 name = savepv( pv );
377         }
378 #endif /* PERLDBf_NONAME */
379
380         total++;
381         if (SAVE_STACK) { /* Store it for later recording  -JH */
382             profstack[profstack_ix++].ptype = ptype;
383 #ifdef PERLDBf_NONAME
384             profstack[profstack_ix++].id = id;
385 #else
386             profstack[profstack_ix++].name = name;
387 #endif 
388             /* Only record the parent's info */
389             if (SAVE_STACK < profstack_ix) {
390                 if (prof_pid == (int)getpid())
391                     prof_dump_until(profstack_ix);
392                 else
393                     perldb = 0;         /* Do not debug the kid. */
394                 profstack_ix = 0;
395             }
396         } else { /* Write it to disk now so's not to eat up core */
397
398             /* Only record the parent's info */
399             if (prof_pid == (int)getpid()) {
400 #ifdef PERLDBf_NONAME
401                 prof_dumpa(ptype, id);
402 #else
403                 prof_dump(ptype, name);
404 #endif 
405                 PerlIO_flush(fp);
406             } else
407                 perldb = 0;             /* Do not debug the kid. */
408         }
409 }
410
411 static U32 default_perldb;
412
413 #ifdef PL_NEEDED
414 #  define defstash PL_defstash
415 #endif
416
417 /* Counts overhead of prof_mark and extra XS call. */
418 static void
419 test_time(clock_t *r, clock_t *u, clock_t *s)
420 {
421     dTHR;
422     CV *cv = perl_get_cv("Devel::DProf::NONESUCH_noxs", FALSE);
423     int i, j, k = 0;
424     HV *oldstash = curstash;
425     struct tms t1, t2;
426     clock_t realtime1, realtime2;
427     U32 ototal = total;
428     U32 ostack = SAVE_STACK;
429     U32 operldb = perldb;
430
431     SAVE_STACK = 1000000;
432     realtime1 = Times(&t1);
433     
434     while (k < 2) {
435         i = 0;
436             /* Disable debugging of perl_call_sv on second pass: */
437         curstash = (k == 0 ? defstash : debstash);
438         perldb = default_perldb;
439         while (++i <= 100) {
440             j = 0;
441             profstack_ix = 0;           /* Do not let the stack grow */
442             while (++j <= 100) {
443 /*              prof_mark( OP_ENTERSUB ); */
444
445                 PUSHMARK( stack_sp );
446                 perl_call_sv( (SV*)cv, G_SCALAR );
447                 stack_sp--;
448 /*              prof_mark( OP_LEAVESUB ); */
449             }
450         }
451         curstash = oldstash;
452         if (k == 0) {                   /* Put time with debugging */
453             realtime2 = Times(&t2);
454             *r = realtime2 - realtime1;
455             *u = t2.tms_utime - t1.tms_utime;
456             *s = t2.tms_stime - t1.tms_stime;
457         } else {                        /* Subtract time without debug */
458             realtime1 = Times(&t1);
459             *r -= realtime1 - realtime2;
460             *u -= t1.tms_utime - t2.tms_utime;
461             *s -= t1.tms_stime - t2.tms_stime;      
462         }
463         k++;
464     }
465     total = ototal;
466     SAVE_STACK = ostack;
467     perldb = operldb;
468 }
469
470 static void
471 prof_recordheader()
472 {
473         clock_t r, u, s;
474
475         /* fp is opened in the BOOT section */
476         PerlIO_printf(fp, "#fOrTyTwO\n" );
477         PerlIO_printf(fp, "$hz=%d;\n", DPROF_HZ );
478         PerlIO_printf(fp, "$XS_VERSION='DProf %s';\n", XS_VERSION );
479         PerlIO_printf(fp, "# All values are given in HZ\n" );
480         test_time(&r, &u, &s);
481         PerlIO_printf(fp, "$over_utime=%ld; $over_stime=%ld; $over_rtime=%ld;\n",
482                 u, s, r);
483         PerlIO_printf(fp, "$over_tests=10000;\n");
484
485         TIMES_LOCATION = PerlIO_tell(fp);
486
487         /* Pad with whitespace. */
488         /* This should be enough even for very large numbers. */
489         PerlIO_printf(fp, "%*s\n", 240 , "");
490
491         PerlIO_printf(fp, "\n");
492         PerlIO_printf(fp, "PART2\n" );
493
494         PerlIO_flush(fp);
495 }
496
497 static void
498 prof_record()
499 {
500         /* fp is opened in the BOOT section */
501
502         /* Now that we know the runtimes, fill them in at the recorded
503            location -JH */
504
505         clock_t r, u, s;
506     
507         if(SAVE_STACK){
508             prof_dump_until(profstack_ix);
509         }
510         PerlIO_seek(fp, TIMES_LOCATION, SEEK_SET);
511         /* Write into reserved 240 bytes: */
512         PerlIO_printf(fp, "$rrun_utime=%ld; $rrun_stime=%ld; $rrun_rtime=%ld;",
513                 prof_end.tms_utime - prof_start.tms_utime - wprof_u,
514                 prof_end.tms_stime - prof_start.tms_stime - wprof_s,
515                 rprof_end - rprof_start - wprof_r );
516         PerlIO_printf(fp, "\n$total_marks=%ld;", total);
517         
518         PerlIO_close( fp );
519 }
520
521 #define NONESUCH()
522
523 static U32 depth = 0;
524
525 static void
526 check_depth(pTHX_ void *foo)
527 {
528     U32 need_depth = (U32)foo;
529     if (need_depth != depth) {
530         if (need_depth > depth) {
531             warn("garbled call depth when profiling");
532         } else {
533             I32 marks = depth - need_depth;
534
535 /*          warn("Check_depth: got %d, expected %d\n", depth, need_depth); */
536             while (marks--) {
537                 prof_mark( OP_DIE );
538             }
539             depth = need_depth;
540         }
541     }
542 }
543
544 #define for_real
545 #ifdef for_real
546
547 XS(XS_DB_sub)
548 {
549         dXSARGS;
550         dORIGMARK;
551         HV *oldstash = curstash;
552
553         SP -= items;
554
555         DBG_SUB_NOTIFY( "XS DBsub(%s)\n", SvPV(Sub, na) );
556
557 #ifndef PERLDBf_NONAME                  /* Was needed on older Perls */
558         sv_setiv( DBsingle, 0 ); /* disable DB single-stepping */
559 #endif 
560
561         SAVEDESTRUCTOR(check_depth, (void*)depth);
562         depth++;
563
564         prof_mark( OP_ENTERSUB );
565         PUSHMARK( ORIGMARK );
566
567 #ifdef G_NODEBUG
568         perl_call_sv( (SV*)SvIV(Sub), GIMME | G_NODEBUG);
569 #else
570         curstash = debstash;    /* To disable debugging of perl_call_sv */
571 #ifdef PERLDBf_NONAME
572         perl_call_sv( (SV*)SvIV(Sub), GIMME );
573 #else
574         perl_call_sv( Sub, GIMME );
575 #endif 
576         curstash = oldstash;
577 #endif 
578
579         prof_mark( OP_LEAVESUB );
580         depth--;
581
582         SPAGAIN;
583         PUTBACK;
584         return;
585 }
586
587 XS(XS_DB_goto)
588 {
589         prof_mark( OP_GOTO );
590         return;
591 }
592
593 #endif /* for_real */
594
595 #ifdef testing
596
597         MODULE = Devel::DProf           PACKAGE = DB
598
599         void
600         sub(...)
601                 PPCODE:
602
603                 dORIGMARK;
604                 HV *oldstash = curstash;
605                 /* SP -= items;  added by xsubpp */
606                 DBG_SUB_NOTIFY( "XS DBsub(%s)\n", SvPV(Sub, na) );
607
608                 sv_setiv( DBsingle, 0 ); /* disable DB single-stepping */
609
610                 prof_mark( OP_ENTERSUB );
611                 PUSHMARK( ORIGMARK );
612
613                 curstash = debstash;    /* To disable debugging of perl_call_sv
614 */
615                 perl_call_sv( Sub, GIMME );
616                 curstash = oldstash;
617
618                 prof_mark( OP_LEAVESUB );
619                 SPAGAIN;
620                 /* PUTBACK;  added by xsubpp */
621
622 #endif /* testing */
623
624 MODULE = Devel::DProf           PACKAGE = Devel::DProf
625
626 void
627 END()
628         PPCODE:
629         if( DBsub ){
630                 /* maybe the process forked--we want only
631                  * the parent's profile.
632                  */
633                 if( prof_pid == (int)getpid() ){
634                         rprof_end = Times(&prof_end);
635                         DBG_TIMER_NOTIFY("Profiler timer is off.\n");
636                         prof_record();
637                 }
638         }
639
640 void
641 NONESUCH()
642
643 BOOT:
644         /* Before we go anywhere make sure we were invoked
645          * properly, else we'll dump core.
646          */
647         if( ! DBsub )
648                 croak("DProf: run perl with -d to use DProf.\n");
649
650         /* When we hook up the XS DB::sub we'll be redefining
651          * the DB::sub from the PM file.  Turn off warnings
652          * while we do this.
653          */
654         {
655                 I32 warn_tmp = dowarn;
656                 dowarn = 0;
657                 newXS("DB::sub", XS_DB_sub, file);
658                 newXS("DB::goto", XS_DB_goto, file);
659                 dowarn = warn_tmp;
660         }
661
662         Sub = GvSV(DBsub);       /* name of current sub */
663         sv_setiv( DBsingle, 0 ); /* disable DB single-stepping */
664
665         {
666             char *buffer = getenv("PERL_DPROF_BUFFER");
667
668             if (buffer) {
669                 SAVE_STACK = atoi(buffer);
670             }
671
672             buffer = getenv("PERL_DPROF_TICKS");
673
674             if (buffer) {
675                 dprof_ticks = atoi(buffer); /* Used under OS/2 only */
676             } else {
677                 dprof_ticks = HZ;
678             }
679         }
680
681         if( (fp = PerlIO_open( "tmon.out", "w" )) == NULL )
682                 croak("DProf: unable to write tmon.out, errno = %d\n", errno );
683 #ifdef PERLDBf_NONAME
684         default_perldb = PERLDBf_NONAME | PERLDBf_SUB; /* no name needed. */
685 #ifdef PERLDBf_GOTO
686         default_perldb = default_perldb | PERLDBf_GOTO;
687 #endif 
688         cv_hash = newHV();
689 #else
690 #  ifdef PERLDBf_SUB
691         default_perldb = PERLDBf_SUB;           /* debug subroutines only. */
692 #  endif
693 #endif
694         prof_pid = (int)getpid();
695
696         New( 0, profstack, profstack_max, PROFANY );
697
698         prof_recordheader();
699
700         DBG_TIMER_NOTIFY("Profiler timer is on.\n");
701         orealtime = rprof_start = Times(&prof_start);
702         otms_utime = prof_start.tms_utime;
703         otms_stime = prof_start.tms_stime;
704         perldb = default_perldb;