Unix.HierarchicalProfiler0.Mod 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. MODULE HierarchicalProfiler0; (** AUTHOR "skoster"; PURPOSE "UnixAOS platform-specific part of the hierarchical profiler"; *)
  2. IMPORT
  3. SYSTEM, Kernel, Unix, Objects, Modules, ProcessInfo, Heaps;
  4. CONST
  5. Initialized = 0;
  6. Running = 1;
  7. Terminating = 2;
  8. Terminated = 3;
  9. Intervall = 1; (* milliseconds *)
  10. TYPE
  11. ProcessTimeArray = POINTER TO ARRAY ProcessInfo.MaxNofProcesses OF HUGEINT;
  12. Callback = PROCEDURE (id : LONGINT; process : Objects.Process; pc, bp, lowAdr, highAdr : ADDRESS);
  13. Poller = OBJECT
  14. VAR
  15. processes, oldProcesses : ARRAY ProcessInfo.MaxNofProcesses OF Objects.Process;
  16. nofProcesses, oldNofProcesses : LONGINT;
  17. times, oldTimes : ProcessTimeArray;
  18. me : Objects.Process;
  19. state : LONGINT;
  20. timer: Kernel.Timer;
  21. NormalGC: PROCEDURE; (*gc that is currently used*)
  22. PROCEDURE &Init;
  23. BEGIN
  24. state := Running;
  25. ProcessInfo.Clear(processes); nofProcesses := 0;
  26. ProcessInfo.Clear(oldProcesses); oldNofProcesses := 0;
  27. NEW(times); Clear(times);
  28. NEW(oldTimes); Clear(oldTimes);
  29. END Init;
  30. PROCEDURE Terminate;
  31. BEGIN {EXCLUSIVE}
  32. IF (state # Terminated) THEN state := Terminating; END;
  33. AWAIT(state = Terminated);
  34. END Terminate;
  35. PROCEDURE Clear(array : ProcessTimeArray);
  36. VAR i : LONGINT;
  37. BEGIN
  38. FOR i := 0 TO LEN(array)-1 DO array[i] := 0; END;
  39. END Clear;
  40. PROCEDURE RanMeanwhile(process : Objects.Process; currentCycles : HUGEINT) : BOOLEAN;
  41. VAR i : LONGINT;
  42. BEGIN
  43. IF ~(process.mode IN {Objects.Running,Objects.Ready}) THEN RETURN FALSE END;
  44. i := 0; WHILE (i < oldNofProcesses) & (oldProcesses[i] # process) DO INC(i); END;
  45. RETURN (i >= oldNofProcesses) OR (oldTimes[i] < currentCycles);
  46. END RanMeanwhile;
  47. PROCEDURE Process;
  48. VAR process : Objects.Process; cycles : Objects.CpuCyclesArray; temp : ProcessTimeArray; i : LONGINT;
  49. BEGIN
  50. NormalGC := Heaps.GC;
  51. Heaps.GC := Nothing; (*disable gc*)
  52. ProcessInfo.GetProcesses(processes, nofProcesses);
  53. (*TRACE(nofProcesses);*)
  54. FOR i := 0 TO nofProcesses - 1 DO
  55. process := processes[i];
  56. Objects.GetCpuCycles(process, cycles, FALSE);
  57. times[i] := cycles[0];
  58. (*TRACE(process,me,cycles[0],process.mode,Objects.Running);*)
  59. (*the damned thing might go into waiting or some other unwanted state before we suspend it todo*)
  60. IF (process # me) & (cycles[0] # 0) & (process.mode = Objects.Running) (* (process.mode # Objects.AwaitingEvent) & (process.mode # Objects.AwaitingCond) & (process.mode < Objects.Suspended) & (process.mode >= Objects.Ready) (*RanMeanwhile(process, times[i]) *) *) THEN
  61. HandleProcess(process);
  62. END;
  63. END;
  64. temp := oldTimes;
  65. oldTimes := times;
  66. times := temp;
  67. ProcessInfo.Copy(processes, oldProcesses);
  68. oldNofProcesses := nofProcesses;
  69. ProcessInfo.Clear(processes);
  70. Heaps.GC := NormalGC; (*re-enable gc*)
  71. END Process;
  72. BEGIN {ACTIVE, PRIORITY(Objects.Realtime)}
  73. NEW(timer);
  74. me := Objects.CurrentProcess();
  75. TRACE('poller starting');
  76. LOOP
  77. WHILE (state = Running) DO
  78. Process;
  79. timer.Sleep(100);
  80. END;
  81. IF (state = Terminating) THEN EXIT; END;
  82. END;
  83. ProcessInfo.Clear(processes);
  84. ProcessInfo.Clear(oldProcesses);
  85. BEGIN {EXCLUSIVE} state := Terminated; END;
  86. END Poller;
  87. VAR
  88. poller : Poller;
  89. callback : Callback;
  90. state : LONGINT;
  91. PROCEDURE Nothing; (*no-op garbage collector*)
  92. BEGIN
  93. END Nothing;
  94. PROCEDURE HandleProcess(process : Objects.Process);
  95. (*VAR context : Kernel32.Context; handle : Kernel32.HANDLE; res : Kernel32.BOOL;*)
  96. VAR
  97. threadId: Unix.Thread_t;
  98. stackBottom, sp, bp: ADDRESS;
  99. context: Unix.McontextDesc;
  100. BEGIN
  101. ASSERT(process # NIL);
  102. threadId:=process.threadId;
  103. (*todo: validate thread ID*)
  104. TRACE('suspending thread',threadId);
  105. Unix.ThrSuspend(threadId);
  106. (*because thread suspending is under a mutex in Unix.Mod, this call is guaranteed to have finished with the handler when it returns.*)
  107. TRACE('suspend successful',threadId);
  108. context:=process.context;
  109. IF (context.r_pc #0) THEN
  110. stackBottom:=Objects.GetStackBottom(process);
  111. sp:=context.r_sp_x;
  112. bp:=context.r_bp;
  113. IF bp<=stackBottom THEN
  114. callback(1, process, context.r_pc,bp,sp, stackBottom );
  115. ELSE
  116. Unix.ThrResume(threadId);
  117. TRACE('bp smaller than stack bottom found',threadId);
  118. END;
  119. END;
  120. TRACE('resuming thread',threadId);
  121. Unix.ThrResume(threadId);
  122. TRACE('successful resume',threadId);
  123. (* handle := process.handle;
  124. IF (handle # Kernel32.NULL) & (handle # Kernel32.InvalidHandleValue) THEN
  125. res := Kernel32.SuspendThread(handle);
  126. IF (res >= 0) THEN
  127. context.ContextFlags := Kernel32.ContextControl+Kernel32.ContextInteger;
  128. res := Kernel32.GetThreadContext(handle, context);
  129. IF (res = Kernel32.True) THEN
  130. IF (context.PC # 0) THEN
  131. stackBottom := Objects.GetStackBottom(process);
  132. bp := context.BP;
  133. sp := context.SP;
  134. ASSERT(context.BP <= stackBottom);
  135. callback(1, process, context.PC, context.BP, context.SP, stackBottom(* LONGINT(0FFFFFFFFH)*) );
  136. END;
  137. END;
  138. res := Kernel32.ResumeThread(handle);
  139. END;
  140. END;
  141. *)
  142. END HandleProcess;
  143. PROCEDURE Enable*(proc : Callback);
  144. BEGIN {EXCLUSIVE}
  145. (*todo: disable gc*)
  146. ASSERT(proc # NIL);
  147. ASSERT((state = Initialized) & (poller = NIL));
  148. callback := proc;
  149. NEW(poller);
  150. state := Running;
  151. END Enable;
  152. PROCEDURE Disable*;
  153. BEGIN {EXCLUSIVE}
  154. (*todo: re-enable gc*)
  155. ASSERT((state = Running) & (poller # NIL));
  156. poller.Terminate;
  157. poller := NIL;
  158. state := Initialized;
  159. END Disable;
  160. PROCEDURE Cleanup;
  161. BEGIN
  162. IF (poller # NIL) THEN poller.Terminate; poller := NIL; END;
  163. END Cleanup;
  164. BEGIN
  165. state := Initialized;
  166. Modules.InstallTermHandler(Cleanup);
  167. END HierarchicalProfiler0.
  168. WMProfiler.Open~
  169. HierarchicalProfiler.Start~
  170. HierarchicalProfiler.Stop~
  171. HierarchicalProfiler.Show~
  172. SystemTools.Free WMProfiler HierarchicalProfiler HierarchicalProfiler0 ~
  173. Test.Busyloop~
  174. Test.PingPongTest~
  175. Debugging.DisableGC~