PageRenderTime 55ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/src/runtime/runtime.c

https://github.com/kfl/mosml
C | 326 lines | 243 code | 50 blank | 33 comment | 32 complexity | d146160e19101512481f6bacc6a434cb MD5 | raw file
Possible License(s): GPL-2.0
  1. /* runtime.c */
  2. #include "config.h"
  3. #include "runtime.h"
  4. #ifdef macintosh
  5. /* 23Nov93 e */
  6. /* 16Mar94 e -- revised to not abuse time manager (!) */
  7. /* 31Aug95 e -- revised to abuse time manager less (!) */
  8. /* 05Sep95 e -- added mosml required stuff: gettimeofday, e_getrusage */
  9. /* Keeping track of time spent
  10. - in gc
  11. - in multifinder
  12. - overall since startup
  13. */
  14. #include <Timer.h>
  15. #include <stdlib.h>
  16. #include <time.h>
  17. #include <utime.h>
  18. #include "alloc.h"
  19. #include "fail.h"
  20. #include "memory.h"
  21. #include "debugger.h"
  22. #include "mlvalues.h"
  23. #include "freelist.h"
  24. #include "gc.h"
  25. #include "major_gc.h"
  26. /* */
  27. #define qRunTimes 8 /* must be at least three for: total, gc, mutlifinder */
  28. #define aMILLION (1000000L)
  29. #if GENERATINGPOWERPC
  30. #pragma options align=mac68k
  31. #endif
  32. typedef struct tinfuRec
  33. {
  34. TMTask TMTask;
  35. short filler;
  36. unsigned long acc_secs;
  37. signed long acc_usecs;
  38. } tinfuRec, *tinfuPtr;
  39. #if GENERATINGPOWERPC
  40. #pragma options align=reset
  41. #endif
  42. static tinfuRec gTimeInfo[qRunTimes];
  43. #define TIMe(n) (gTimeInfo[n].TMTask)
  44. /* 09Jan95 e */
  45. static TimerUPP tmt_handlerUPP = NULL;
  46. #if powerc
  47. static pascal void tmt_handler(TMTaskPtr a1)
  48. {
  49. ((tinfuPtr )a1)->acc_secs++;
  50. PrimeTime((QElemPtr )a1, -aMILLION);
  51. }
  52. #else
  53. #ifndef __MWERKS__
  54. static pascal void tmt_handler(void)
  55. {
  56. asm
  57. {
  58. ADDQ.L #1, tinfuRec.acc_secs(a1)
  59. MOVE.L A1, A0
  60. MOVE.L #-aMILLION, D0
  61. DC.W 0xA05A ; PrimeTime
  62. }
  63. }
  64. #else
  65. asm static pascal void tmt_handler(void)
  66. {
  67. ADDQ.L #1, 0x18(A1) // tinfuRec.acc_secs(a1)
  68. MOVE.L A1, A0
  69. MOVE.L #-aMILLION, D0
  70. DC.W 0xA05A // PrimeTime
  71. RTS
  72. }
  73. #endif
  74. #endif
  75. static void cancel_timers(void)
  76. { int i;
  77. for ( i = 0; i < qRunTimes; i++ )
  78. // always! 31Aug95 e -- if (TIMe(i).tmAddr != NULL && TIMe(i).qType < 0 )
  79. { RmvTime((QElemPtr )&TIMe(i));
  80. TIMe(i).tmAddr = NULL;
  81. }
  82. }
  83. static time_t systime_init;
  84. void init_timers(void)
  85. { int i;
  86. if (tmt_handlerUPP == NULL) tmt_handlerUPP = NewTimerProc(tmt_handler);
  87. for ( i = 0; i < qRunTimes; i++ )
  88. if (TIMe(i).tmAddr == NULL)
  89. { TIMe(i).tmAddr = tmt_handlerUPP;
  90. // only 0, 31Aug95 e -- InsXTime((QElemPtr )&TIMe(i));
  91. if ( i == 0 )
  92. { _atexit(cancel_timers);
  93. InsXTime((QElemPtr )&TIMe(0));
  94. systime_init = time(NULL);
  95. PrimeTime((QElemPtr )&TIMe(0), -aMILLION);
  96. }
  97. }
  98. }
  99. void beg_runtime(int i)
  100. { tinfuPtr p;
  101. if ( 0 >= i || i >= qRunTimes ) Debugger(); /* coding error */
  102. p = &gTimeInfo[i];
  103. p->TMTask.tmWakeUp = 0;
  104. p->TMTask.tmReserved = 0;
  105. InsXTime((QElemPtr )&(p->TMTask));
  106. PrimeTime((QElemPtr )&(p->TMTask), -aMILLION);
  107. }
  108. void acc_runtime(int i)
  109. { tinfuPtr p;
  110. if ( 0 > i || i >= qRunTimes ) Debugger(); /* coding error */
  111. p = &gTimeInfo[i];
  112. RmvTime((QElemPtr )&(p->TMTask));
  113. p->acc_usecs += aMILLION + p->TMTask.tmCount;
  114. if (p->acc_usecs >= aMILLION)
  115. {
  116. p->acc_secs += 1;
  117. p->acc_usecs -= aMILLION;
  118. }
  119. else if (p->acc_usecs < 0)
  120. {
  121. p->acc_secs -= 1;
  122. p->acc_usecs += aMILLION;
  123. }
  124. }
  125. static double double_zero = (double )0;
  126. value get_timer(value x) /* ML */
  127. {
  128. unsigned int i = Long_val(x);
  129. tinfuPtr p;
  130. if ( 0 > i || i >= qRunTimes) return copy_double(double_zero);
  131. p = &gTimeInfo[i];
  132. if (i == 0)
  133. {
  134. RmvTime((QElemPtr )&(p->TMTask));
  135. p->acc_usecs = aMILLION + p->TMTask.tmCount;
  136. InsXTime((QElemPtr )&(p->TMTask));
  137. PrimeTime((QElemPtr )&(p->TMTask), 0);
  138. }
  139. return copy_double(p->acc_secs + (p->acc_usecs / (double )aMILLION));
  140. }
  141. value beg_timer(value x) /* ML */
  142. {
  143. unsigned int i = Long_val(x);
  144. if (i >= qRunTimes || i <= 2) return Val_false;
  145. beg_runtime(i);
  146. return Val_true;
  147. }
  148. value end_timer(value x) /* ML */
  149. {
  150. unsigned int i = Long_val(x);
  151. if (i >= qRunTimes || i <= 2) return Val_false;
  152. acc_runtime(i);
  153. return Val_true;
  154. }
  155. value clr_timer(value x) /* ML */
  156. {
  157. unsigned int i = Long_val(x);
  158. tinfuPtr p;
  159. if (i >= qRunTimes || i <= 2) return Val_false;
  160. p = &gTimeInfo[i];
  161. p->acc_secs = 0;
  162. p->acc_usecs = 0;
  163. return Val_true;
  164. }
  165. /* runtime stats */
  166. value e_getrusage( void )
  167. {
  168. tinfuPtr p;
  169. unsigned long rts, sts, gts, uts;
  170. long rtu, stu, gtu, utu;
  171. value res = alloc (6, 0);
  172. /* snapshot run timer */
  173. p = &gTimeInfo[0];
  174. RmvTime((QElemPtr )&(p->TMTask));
  175. rts = p->acc_secs; // elapsed time
  176. rtu = p->acc_usecs + aMILLION + p->TMTask.tmCount;
  177. InsXTime((QElemPtr )&(p->TMTask));
  178. PrimeTime((QElemPtr )&(p->TMTask), 0);
  179. /* compute "user" time */
  180. gts = gTimeInfo[1].acc_secs; // gc time
  181. gtu = gTimeInfo[1].acc_usecs;
  182. sts = gTimeInfo[2].acc_secs; // multifinder time
  183. stu = gTimeInfo[2].acc_usecs;
  184. uts = (rts - sts) - gts;
  185. utu = (rtu - stu) - gtu;
  186. while (utu < 0) { utu += aMILLION; uts -= 1; }
  187. while (utu >= aMILLION) { utu -= aMILLION; uts += 1; }
  188. /* pathological case at startup really fries mosml... */
  189. if (uts > 0x3FFFFFFF)
  190. {
  191. uts = 0;
  192. utu = 1;
  193. }
  194. /* fill in SML record */
  195. Field (res, 0) = Val_long (gts); // "gc"
  196. Field (res, 1) = Val_long (gtu);
  197. Field (res, 2) = Val_long (sts); // "system"
  198. Field (res, 3) = Val_long (stu);
  199. Field (res, 4) = Val_long (uts); // "user"
  200. Field (res, 5) = Val_long (utu);
  201. return res;
  202. }
  203. /* end of MacOS specific code */
  204. #else
  205. /* DOS, Unix, Win32 */
  206. #ifdef WIN32
  207. #include <sys/timeb.h>
  208. #include <sys/utime.h>
  209. #else
  210. #include <sys/times.h>
  211. #include <sys/time.h>
  212. #include <sys/resource.h>
  213. #include <unistd.h>
  214. #endif
  215. struct mosml_timeval gc_time = { (long) 0, (long) 0 };
  216. void beg_gc_time(void)
  217. {
  218. #ifdef WIN32
  219. /*
  220. // Here I return sysTime = usrTime.
  221. // Perhaps, win32 enables sysTime and usrTime to be mesured
  222. // in an accurate way...
  223. // Sergei Romanenko
  224. */
  225. struct timeb t;
  226. ftime(&t);
  227. gc_time.tv_sec -= t.time;
  228. gc_time.tv_usec -= ((long) t.millitm) * 1000;
  229. #elif defined(hpux) || defined(__svr4__)
  230. struct tms buffer;
  231. long persec = sysconf(_SC_CLK_TCK);
  232. times(&buffer);
  233. gc_time.tv_sec -= buffer.tms_utime / persec;
  234. gc_time.tv_usec -= (buffer.tms_utime % persec) * (1000000 / persec);
  235. #else
  236. struct rusage rusages;
  237. getrusage(RUSAGE_SELF, &rusages);
  238. gc_time.tv_sec -= rusages.ru_utime.tv_sec;
  239. gc_time.tv_usec -= rusages.ru_utime.tv_usec;
  240. #endif
  241. if (gc_time.tv_usec < 0) {
  242. gc_time.tv_usec += 1000000;
  243. gc_time.tv_sec -= 1;
  244. }
  245. }
  246. void end_gc_time(void)
  247. {
  248. #ifdef WIN32
  249. /*
  250. // Here I return sysTime = usrTime.
  251. // Perhaps, win32 enables sysTime and usrTime to be mesured
  252. // in an accurate way...
  253. // Sergei Romanenko
  254. */
  255. struct timeb t;
  256. ftime(&t);
  257. gc_time.tv_sec += t.time;
  258. gc_time.tv_usec += ((long) t.millitm) * 1000;
  259. #elif defined(hpux) || defined(__svr4__)
  260. struct tms buffer;
  261. long persec = sysconf(_SC_CLK_TCK);
  262. times(&buffer);
  263. gc_time.tv_sec += buffer.tms_utime / persec;
  264. gc_time.tv_usec += (buffer.tms_utime % persec) * (1000000 / persec);
  265. #else
  266. struct rusage rusages;
  267. getrusage(RUSAGE_SELF, &rusages);
  268. gc_time.tv_sec += rusages.ru_utime.tv_sec;
  269. gc_time.tv_usec += rusages.ru_utime.tv_usec;
  270. #endif
  271. if (gc_time.tv_usec >= 1000000) {
  272. gc_time.tv_usec -= 1000000;
  273. gc_time.tv_sec += 1;
  274. }
  275. }
  276. #endif