profiler.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. profiler.c
  5. Abstract:
  6. This module implements profiler interrupt support at the hardware level.
  7. Author:
  8. Chris Stevens 1-Jul-2013
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/kernel.h>
  16. #include "profiler.h"
  17. #include "timer.h"
  18. #include "intrupt.h"
  19. //
  20. // ---------------------------------------------------------------- Definitions
  21. //
  22. //
  23. // Define the default profiler rate in 100ns. As the profiler is backed by the
  24. // RTC on x86, the fastest sample rate is 122 microseconds.
  25. //
  26. #define DEFAULT_PROFILER_RATE 50000
  27. //
  28. // ----------------------------------------------- Internal Function Prototypes
  29. //
  30. //
  31. // ------------------------------------------------------ Data Type Definitions
  32. //
  33. //
  34. // -------------------------------------------------------------------- Globals
  35. //
  36. //
  37. // Store a variable indicating whether profiler interrupts are broadcasted.
  38. //
  39. BOOL HlBroadcastProfilerInterrupts = FALSE;
  40. //
  41. // ------------------------------------------------------------------ Functions
  42. //
  43. KSTATUS
  44. HlStartProfilerTimer (
  45. VOID
  46. )
  47. /*++
  48. Routine Description:
  49. This routine activates the profiler by arming the profiler timer.
  50. Arguments:
  51. None.
  52. Return Value:
  53. Status code.
  54. --*/
  55. {
  56. KSTATUS Status;
  57. ULONGLONG TickCount;
  58. //
  59. // Fail if the profiler timer is not available.
  60. //
  61. if (HlProfilerTimer == NULL) {
  62. return STATUS_NOT_SUPPORTED;
  63. }
  64. //
  65. // Fire up the profiler timer.
  66. //
  67. TickCount = HlpTimerTimeToTicks(HlProfilerTimer, DEFAULT_PROFILER_RATE);
  68. Status = HlpTimerArm(HlProfilerTimer, TimerModePeriodic, TickCount);
  69. return Status;
  70. }
  71. VOID
  72. HlStopProfilerTimer (
  73. VOID
  74. )
  75. /*++
  76. Routine Description:
  77. This routine stops the profiler by disarming the profiler timer.
  78. Arguments:
  79. None.
  80. Return Value:
  81. None.
  82. --*/
  83. {
  84. //
  85. // Disarm the profiler timer if it exists.
  86. //
  87. if (HlProfilerTimer != NULL) {
  88. HlpTimerDisarm(HlProfilerTimer);
  89. }
  90. return;
  91. }
  92. KSTATUS
  93. HlpTimerInitializeProfiler (
  94. VOID
  95. )
  96. /*++
  97. Routine Description:
  98. This routine initializes the system profiler source. It does not start the
  99. profiler timer.
  100. Arguments:
  101. None.
  102. Return Value:
  103. Status code.
  104. --*/
  105. {
  106. ULONG Processor;
  107. PKINTERRUPT ProfilerInterrupt;
  108. INTERRUPT_LINE_STATE State;
  109. KSTATUS Status;
  110. PROCESSOR_SET Target;
  111. if (HlProfilerTimer == NULL) {
  112. return STATUS_SUCCESS;
  113. }
  114. Processor = KeGetCurrentProcessorNumber();
  115. if (Processor == 0) {
  116. //
  117. // Configure the interrupt for the profiler timer.
  118. //
  119. RtlZeroMemory(&Target, sizeof(PROCESSOR_SET));
  120. Target.Target = ProcessorTargetSelf;
  121. State.Mode = HlProfilerTimer->Interrupt.TriggerMode;
  122. State.Polarity = HlProfilerTimer->Interrupt.ActiveLevel;
  123. State.Flags = INTERRUPT_LINE_STATE_FLAG_ENABLED;
  124. HlpInterruptGetStandardCpuLine(&(State.Output));
  125. ProfilerInterrupt = HlpInterruptGetProfilerKInterrupt();
  126. HlProfilerTimer->InterruptRunLevel = ProfilerInterrupt->RunLevel;
  127. Status = HlpInterruptSetLineState(&(HlProfilerTimer->Interrupt.Line),
  128. &State,
  129. ProfilerInterrupt,
  130. &Target,
  131. NULL,
  132. 0);
  133. if (!KSUCCESS(Status)) {
  134. goto InitializeProfilerEnd;
  135. }
  136. } else {
  137. //
  138. // Always enable broadcast if there are additional processors.
  139. //
  140. ASSERT((HlProfilerTimer->Features & TIMER_FEATURE_PER_PROCESSOR) == 0);
  141. HlBroadcastProfilerInterrupts = TRUE;
  142. }
  143. Status = STATUS_SUCCESS;
  144. InitializeProfilerEnd:
  145. return Status;
  146. }
  147. INTERRUPT_STATUS
  148. HlpProfilerInterruptHandler (
  149. PVOID Context
  150. )
  151. /*++
  152. Routine Description:
  153. This routine is the main profiler ISR.
  154. Arguments:
  155. Context - Supplies a pointer to the current trap frame.
  156. Return Value:
  157. Claimed always.
  158. --*/
  159. {
  160. ULONG Processor;
  161. PROCESSOR_SET Processors;
  162. ASSERT(HlProfilerTimer != NULL);
  163. //
  164. // If this is P0, acknowledge the timer and send it off to the other
  165. // processors if broadcast is set.
  166. //
  167. Processor = KeGetCurrentProcessorNumber();
  168. if (Processor == 0) {
  169. HlpTimerAcknowledgeInterrupt(HlProfilerTimer);
  170. if (HlBroadcastProfilerInterrupts != FALSE) {
  171. Processors.Target = ProcessorTargetAllExcludingSelf;
  172. HlSendIpi(IpiTypeProfiler, &Processors);
  173. }
  174. }
  175. SpProfilerInterrupt(Context);
  176. return InterruptStatusClaimed;
  177. }
  178. //
  179. // --------------------------------------------------------- Internal Functions
  180. //