2
0

Unix.HierarchicalProfiler0.Mod 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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. 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
  60. HandleProcess(process);
  61. END;
  62. END;
  63. temp := oldTimes;
  64. oldTimes := times;
  65. times := temp;
  66. ProcessInfo.Copy(processes, oldProcesses);
  67. oldNofProcesses := nofProcesses;
  68. ProcessInfo.Clear(processes);
  69. Heaps.GC := NormalGC; (*re-enable gc*)
  70. END Process;
  71. BEGIN {ACTIVE, PRIORITY(Objects.Realtime)}
  72. NEW(timer);
  73. me := Objects.CurrentProcess();
  74. TRACE('poller starting');
  75. LOOP
  76. WHILE (state = Running) DO
  77. Process;
  78. timer.Sleep(100);
  79. END;
  80. IF (state = Terminating) THEN EXIT; END;
  81. END;
  82. ProcessInfo.Clear(processes);
  83. ProcessInfo.Clear(oldProcesses);
  84. BEGIN {EXCLUSIVE} state := Terminated; END;
  85. END Poller;
  86. VAR
  87. poller : Poller;
  88. callback : Callback;
  89. state : LONGINT;
  90. PROCEDURE Nothing; (*no-op garbage collector*)
  91. BEGIN
  92. END Nothing;
  93. PROCEDURE HandleProcess(process : Objects.Process);
  94. (*VAR context : Kernel32.Context; handle : Kernel32.HANDLE; res : Kernel32.BOOL;*)
  95. VAR
  96. threadId: Unix.Thread_t;
  97. stackBottom, sp, bp: ADDRESS;
  98. context: Unix.McontextDesc;
  99. BEGIN
  100. ASSERT(process # NIL);
  101. threadId:=process.threadId;
  102. (*from check at callsite it's guaranteed that the process is running (mode=Objects.Running) *)
  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. context:=process.context;
  108. IF (context.r_pc #0) THEN
  109. stackBottom:=Objects.GetStackBottom(process);
  110. sp:=context.r_sp_x;
  111. bp:=context.r_bp;
  112. IF bp<=stackBottom THEN
  113. callback(1, process, context.r_pc,bp,sp, stackBottom );
  114. ELSE
  115. Unix.ThrResume(threadId);
  116. TRACE('bp smaller than stack bottom found',threadId);
  117. END;
  118. END;
  119. TRACE('resuming thread',threadId);
  120. Unix.ThrResume(threadId);
  121. TRACE('successful resume',threadId);
  122. (* handle := process.handle;
  123. IF (handle # Kernel32.NULL) & (handle # Kernel32.InvalidHandleValue) THEN
  124. res := Kernel32.SuspendThread(handle);
  125. IF (res >= 0) THEN
  126. context.ContextFlags := Kernel32.ContextControl+Kernel32.ContextInteger;
  127. res := Kernel32.GetThreadContext(handle, context);
  128. IF (res = Kernel32.True) THEN
  129. IF (context.PC # 0) THEN
  130. stackBottom := Objects.GetStackBottom(process);
  131. bp := context.BP;
  132. sp := context.SP;
  133. ASSERT(context.BP <= stackBottom);
  134. callback(1, process, context.PC, context.BP, context.SP, stackBottom(* LONGINT(0FFFFFFFFH)*) );
  135. END;
  136. END;
  137. res := Kernel32.ResumeThread(handle);
  138. END;
  139. END;
  140. *)
  141. END HandleProcess;
  142. PROCEDURE Enable*(proc : Callback);
  143. BEGIN {EXCLUSIVE}
  144. (*todo: disable gc*)
  145. ASSERT(proc # NIL);
  146. ASSERT((state = Initialized) & (poller = NIL));
  147. callback := proc;
  148. NEW(poller);
  149. state := Running;
  150. END Enable;
  151. PROCEDURE Disable*;
  152. BEGIN {EXCLUSIVE}
  153. (*todo: re-enable gc*)
  154. ASSERT((state = Running) & (poller # NIL));
  155. poller.Terminate;
  156. poller := NIL;
  157. state := Initialized;
  158. END Disable;
  159. PROCEDURE Cleanup;
  160. BEGIN
  161. IF (poller # NIL) THEN poller.Terminate; poller := NIL; END;
  162. END Cleanup;
  163. BEGIN
  164. state := Initialized;
  165. Modules.InstallTermHandler(Cleanup);
  166. END HierarchicalProfiler0.
  167. WMProfiler.Open~
  168. HierarchicalProfiler.Start~
  169. HierarchicalProfiler.Stop~
  170. HierarchicalProfiler.Show~
  171. SystemTools.Free WMProfiler HierarchicalProfiler HierarchicalProfiler0 ~
  172. Test.Busyloop~
  173. Debugging.DisableGC~