326 lines · 7.1 KB · C
RawDownload
/* runtime.c  */ #include "config.h" #include "runtime.h" #ifdef macintosh /* 23Nov93  e *//* 16Mar94  e  -- revised to not abuse time manager (!) *//* 31Aug95  e  -- revised to abuse time manager less (!) *//* 05Sep95  e  -- added mosml required stuff: gettimeofday, e_getrusage */ /* Keeping track of time spent - in gc - in multifinder - overall since startup*/ #include <Timer.h>#include <stdlib.h> #include <time.h>#include <utime.h> #include "alloc.h"#include "fail.h"#include "memory.h"#include "debugger.h"#include "mlvalues.h"#include "freelist.h"#include "gc.h"#include "major_gc.h" /* */ #define qRunTimes 8 /* must be at least three for: total, gc, mutlifinder */ #define aMILLION (1000000L) #if GENERATINGPOWERPC#pragma options align=mac68k#endif typedef struct tinfuRec{  TMTask TMTask;  short filler;  unsigned long  acc_secs;    signed long acc_usecs;} tinfuRec, *tinfuPtr; #if GENERATINGPOWERPC#pragma options align=reset#endif static tinfuRec gTimeInfo[qRunTimes]; #define TIMe(n) (gTimeInfo[n].TMTask) /* 09Jan95 e */ static TimerUPP tmt_handlerUPP = NULL; #if powercstatic pascal void tmt_handler(TMTaskPtr a1){  ((tinfuPtr )a1)->acc_secs++;  PrimeTime((QElemPtr )a1, -aMILLION);}#else#ifndef __MWERKS__static pascal void tmt_handler(void){  asm  {    ADDQ.L #1, tinfuRec.acc_secs(a1)    MOVE.L A1, A0    MOVE.L #-aMILLION, D0    DC.W 0xA05A ; PrimeTime  }}#elseasm static pascal void tmt_handler(void){    ADDQ.L #1, 0x18(A1) // tinfuRec.acc_secs(a1)    MOVE.L A1, A0    MOVE.L #-aMILLION, D0    DC.W 0xA05A // PrimeTime    RTS}#endif#endif static void cancel_timers(void){ int i;  for ( i = 0; i < qRunTimes; i++ )    // always! 31Aug95 e -- if (TIMe(i).tmAddr != NULL && TIMe(i).qType < 0 )    { RmvTime((QElemPtr )&TIMe(i));      TIMe(i).tmAddr = NULL;    }} static time_t systime_init; void init_timers(void){ int i;  if (tmt_handlerUPP == NULL) tmt_handlerUPP = NewTimerProc(tmt_handler);  for ( i = 0; i < qRunTimes; i++ )    if (TIMe(i).tmAddr == NULL)    { TIMe(i).tmAddr = tmt_handlerUPP;      // only 0, 31Aug95 e -- InsXTime((QElemPtr )&TIMe(i));      if ( i == 0 )      { _atexit(cancel_timers);        InsXTime((QElemPtr )&TIMe(0));        systime_init = time(NULL);        PrimeTime((QElemPtr )&TIMe(0), -aMILLION);      }    }} void beg_runtime(int i){ tinfuPtr p;  if ( 0 >= i || i >= qRunTimes ) Debugger(); /* coding error */  p = &gTimeInfo[i];  p->TMTask.tmWakeUp = 0;  p->TMTask.tmReserved = 0;  InsXTime((QElemPtr )&(p->TMTask));  PrimeTime((QElemPtr )&(p->TMTask), -aMILLION);} void acc_runtime(int i){ tinfuPtr p;  if ( 0 > i || i >= qRunTimes ) Debugger(); /* coding error */  p = &gTimeInfo[i];  RmvTime((QElemPtr )&(p->TMTask));  p->acc_usecs += aMILLION + p->TMTask.tmCount;  if (p->acc_usecs >= aMILLION)  {    p->acc_secs += 1;    p->acc_usecs -= aMILLION;  }  else if (p->acc_usecs < 0)  {    p->acc_secs -= 1;    p->acc_usecs += aMILLION;  }} static double double_zero = (double )0; value get_timer(value x)                          /* ML */{  unsigned int i = Long_val(x);  tinfuPtr p;   if ( 0 > i || i >= qRunTimes) return copy_double(double_zero);  p = &gTimeInfo[i];  if (i == 0)  {    RmvTime((QElemPtr )&(p->TMTask));    p->acc_usecs = aMILLION + p->TMTask.tmCount;    InsXTime((QElemPtr )&(p->TMTask));    PrimeTime((QElemPtr )&(p->TMTask), 0);  }  return copy_double(p->acc_secs + (p->acc_usecs / (double )aMILLION));} value beg_timer(value x)                          /* ML */{  unsigned int i = Long_val(x);   if (i >= qRunTimes || i <= 2) return Val_false;  beg_runtime(i);  return Val_true;} value end_timer(value x)                          /* ML */{  unsigned int i = Long_val(x);   if (i >= qRunTimes || i <= 2) return Val_false;  acc_runtime(i);  return Val_true;} value clr_timer(value x)                          /* ML */{  unsigned int i = Long_val(x);  tinfuPtr p;   if (i >= qRunTimes || i <= 2) return Val_false;  p = &gTimeInfo[i];  p->acc_secs  = 0;  p->acc_usecs = 0;  return Val_true;} /* runtime stats */ value e_getrusage( void ){  tinfuPtr p;  unsigned long rts, sts, gts, uts;           long rtu, stu, gtu, utu;  value res = alloc (6, 0);  /* snapshot run timer */  p = &gTimeInfo[0];  RmvTime((QElemPtr )&(p->TMTask));  rts = p->acc_secs;            // elapsed time  rtu = p->acc_usecs + aMILLION + p->TMTask.tmCount;  InsXTime((QElemPtr )&(p->TMTask));  PrimeTime((QElemPtr )&(p->TMTask), 0);  /* compute "user" time */  gts = gTimeInfo[1].acc_secs;  // gc time  gtu = gTimeInfo[1].acc_usecs;  sts = gTimeInfo[2].acc_secs;  // multifinder time  stu = gTimeInfo[2].acc_usecs;  uts = (rts - sts) - gts;  utu = (rtu - stu) - gtu;  while (utu < 0)         { utu += aMILLION; uts -= 1; }  while (utu >= aMILLION) { utu -= aMILLION; uts += 1; }  /* pathological case at startup really fries mosml... */  if (uts > 0x3FFFFFFF)  {    uts = 0;    utu = 1;  }  /* fill in SML record */  Field (res, 0) = Val_long (gts);  // "gc"  Field (res, 1) = Val_long (gtu);  Field (res, 2) = Val_long (sts);  // "system"  Field (res, 3) = Val_long (stu);  Field (res, 4) = Val_long (uts);  // "user"  Field (res, 5) = Val_long (utu);  return res;} /* end of MacOS specific code */ #else /* DOS, Unix, Win32 */ #ifdef WIN32#include <sys/timeb.h>#include <sys/utime.h>#else#include <sys/times.h>    #include <sys/time.h>#include <sys/resource.h>#include <unistd.h>   #endif struct mosml_timeval gc_time = { (long) 0, (long) 0 }; void beg_gc_time(void){#ifdef WIN32  /*  // Here I return sysTime = usrTime.  // Perhaps, win32 enables sysTime and usrTime to be mesured  // in an accurate way...  //  Sergei Romanenko  */  struct timeb t;  ftime(&t);  gc_time.tv_sec  -=  t.time;  gc_time.tv_usec -= ((long) t.millitm) * 1000;#elif defined(hpux) || defined(__svr4__) || defined(plan9)  struct tms buffer;   long persec = sysconf(_SC_CLK_TCK);  times(&buffer);  gc_time.tv_sec  -= buffer.tms_utime / persec;  gc_time.tv_usec -= (buffer.tms_utime % persec) * (1000000 / persec);#else  struct rusage rusages;   getrusage(RUSAGE_SELF, &rusages);  gc_time.tv_sec  -= rusages.ru_utime.tv_sec;  gc_time.tv_usec -= rusages.ru_utime.tv_usec;#endif   if (gc_time.tv_usec < 0) {    gc_time.tv_usec += 1000000;    gc_time.tv_sec  -= 1;  }} void end_gc_time(void){#ifdef WIN32  /*  // Here I return sysTime = usrTime.  // Perhaps, win32 enables sysTime and usrTime to be mesured  // in an accurate way...  //  Sergei Romanenko  */  struct timeb t;  ftime(&t);  gc_time.tv_sec  +=  t.time;  gc_time.tv_usec += ((long) t.millitm) * 1000;#elif defined(hpux) || defined(__svr4__) || defined(plan9)  struct tms buffer;   long persec = sysconf(_SC_CLK_TCK);  times(&buffer);  gc_time.tv_sec  += buffer.tms_utime / persec;  gc_time.tv_usec += (buffer.tms_utime % persec) * (1000000 / persec);#else  struct rusage rusages;   getrusage(RUSAGE_SELF, &rusages);  gc_time.tv_sec  += rusages.ru_utime.tv_sec;  gc_time.tv_usec += rusages.ru_utime.tv_usec;#endif   if (gc_time.tv_usec >= 1000000) {    gc_time.tv_usec -= 1000000;    gc_time.tv_sec  += 1;  } } #endif