profiler.c 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. profiler.c
  5. Abstract:
  6. This module implements system profiling support.
  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 <minoca/kernel/kdebug.h>
  17. #include "spp.h"
  18. //
  19. // ---------------------------------------------------------------- Definitions
  20. //
  21. #define SP_ALLOCATION_TAG 0x21217053 // '!!pS'
  22. //
  23. // Define the length of the scratch buffer within the profiler buffer.
  24. //
  25. #define SCRATCH_BUFFER_LENGTH 200
  26. //
  27. // Define the size of the profiler buffer.
  28. //
  29. #define PROFILER_BUFFER_LENGTH (128 * 1024)
  30. //
  31. // Define the period between memory statistics updates, in microseoncds.
  32. //
  33. #define MEMORY_STATISTICS_TIMER_PERIOD (1000 * MICROSECONDS_PER_MILLISECOND)
  34. //
  35. // Define the number of buffers required to track memory profiling data.
  36. //
  37. #define MEMORY_BUFFER_COUNT 3
  38. //
  39. // Define the buffer size for a new process or thread.
  40. //
  41. #define PROFILER_PROCESS_INFORMATION_SIZE 1024
  42. #define PROFILER_THREAD_INFORMATION_SIZE 1024
  43. //
  44. // ------------------------------------------------------ Data Type Definitions
  45. //
  46. /*++
  47. Structure Description:
  48. This structures defines the system profiler's collection buffer.
  49. Members:
  50. Buffer - Stores a byte array of profiler data ready to be consumed. This is
  51. a ring buffer.
  52. ProducerIndex - Stores the index into the buffer that the data producer
  53. will write to next.
  54. ConsumerIndex - Stores the index into the buffer that the consumer will
  55. read from next.
  56. ConsumerStopIndex - Stores the index into the buffer that the consumer will
  57. read up to before completing a round of consuming.
  58. Scratch - Supplies a byte array used as a temporary holding place for data,
  59. allowing data collection to be performed with sequential writes before
  60. copying the data to the ring buffer.
  61. --*/
  62. typedef struct _PROFILER_BUFFER {
  63. BYTE Buffer[PROFILER_BUFFER_LENGTH];
  64. ULONG ProducerIndex;
  65. ULONG ConsumerIndex;
  66. ULONG ConsumerStopIndex;
  67. BYTE Scratch[SCRATCH_BUFFER_LENGTH];
  68. } PROFILER_BUFFER, *PPROFILER_BUFFER;
  69. /*++
  70. Structure Description:
  71. This structure defines a memory statistics collection buffer for the
  72. system profiler.
  73. Members:
  74. Buffer - Stores a byte array of memory statistics data.
  75. BufferSize - Stores the size of the buffer, in bytes.
  76. --*/
  77. typedef struct _MEMORY_BUFFER {
  78. BYTE *Buffer;
  79. ULONG BufferSize;
  80. ULONG ConsumerIndex;
  81. } MEMORY_BUFFER, *PMEMORY_BUFFER;
  82. /*++
  83. Structure Description:
  84. This structure defines the system's memory profiling state.
  85. Members:
  86. MemoryBuffers - Stores an array of points to memory buffers.
  87. ConsumerActive - Stores a boolean indicating whether or not the consumer
  88. is active.
  89. ConsumerIndex - Stores the index of the memory buffer that was last
  90. consumed or is actively being consumed.
  91. ReadyIndex - Stores the index of the next buffer from which the consumer
  92. should read.
  93. ProducerIndex - Stores the index of the next buffer to which the producer
  94. should write.
  95. Timer - Stores a pointer to the timer that controls production.
  96. ThreadAlive - Stores a boolean indicating whether the thread is alive or
  97. not.
  98. --*/
  99. typedef struct _MEMORY_PROFILER {
  100. MEMORY_BUFFER MemoryBuffers[MEMORY_BUFFER_COUNT];
  101. BOOL ConsumerActive;
  102. ULONG ConsumerIndex;
  103. ULONG ReadyIndex;
  104. ULONG ProducerIndex;
  105. PKTIMER Timer;
  106. volatile BOOL ThreadAlive;
  107. } MEMORY_PROFILER, *PMEMORY_PROFILER;
  108. //
  109. // ----------------------------------------------- Internal Function Prototypes
  110. //
  111. BOOL
  112. SppWriteProfilerBuffer (
  113. PPROFILER_BUFFER ProfilerBuffer,
  114. BYTE *Data,
  115. ULONG Length
  116. );
  117. BOOL
  118. SppReadProfilerBuffer (
  119. PPROFILER_BUFFER ProfilerBuffer,
  120. BYTE *Data,
  121. PULONG DataLength
  122. );
  123. ULONG
  124. SppReadProfilerData (
  125. BYTE *Destination,
  126. BYTE *Source,
  127. ULONG ByteCount,
  128. PULONG BytesRemaining
  129. );
  130. KSTATUS
  131. SppInitializeStackSampling (
  132. VOID
  133. );
  134. VOID
  135. SppDestroyStackSampling (
  136. ULONG Phase
  137. );
  138. KSTATUS
  139. SppInitializeMemoryStatistics (
  140. VOID
  141. );
  142. VOID
  143. SppDestroyMemoryStatistics (
  144. ULONG Phase
  145. );
  146. VOID
  147. SppMemoryStatisticsThread (
  148. PVOID Parameter
  149. );
  150. KSTATUS
  151. SppInitializeThreadStatistics (
  152. VOID
  153. );
  154. VOID
  155. SppSendInitialProcesses (
  156. VOID
  157. );
  158. KSTATUS
  159. SppSendInitialThreads (
  160. PROCESS_ID ProcessId
  161. );
  162. VOID
  163. SppProcessNewProcess (
  164. PROCESS_ID ProcessId
  165. );
  166. VOID
  167. SppProcessNewThread (
  168. PROCESS_ID ProcessId,
  169. THREAD_ID ThreadId
  170. );
  171. VOID
  172. SppDestroyThreadStatistics (
  173. ULONG Phase
  174. );
  175. VOID
  176. SppCollectThreadStatistic (
  177. PKTHREAD Thread,
  178. PPROCESSOR_BLOCK Processor,
  179. SCHEDULER_REASON ScheduleOutReason
  180. );
  181. //
  182. // -------------------------------------------------------------------- Globals
  183. //
  184. //
  185. // Stores a value indicating whether or not profiling is enabled for system
  186. // initialization. Can be set with PROFILER_TYPE_FLAG_* values.
  187. //
  188. ULONG SpEarlyEnabledFlags = 0x0;
  189. //
  190. // Stores a value indicating which types of profiling are enabled.
  191. //
  192. ULONG SpEnabledFlags;
  193. //
  194. // Stores a pointer to a queued lock protecting access to the profiling status
  195. // variables.
  196. //
  197. PQUEUED_LOCK SpProfilingQueuedLock;
  198. //
  199. // Structures that store stack sampling data.
  200. //
  201. PPROFILER_BUFFER *SpStackSamplingArray;
  202. ULONG SpStackSamplingArraySize;
  203. //
  204. // Stores a pointer to a structure that tracks memory statistics profiling.
  205. //
  206. PMEMORY_PROFILER SpMemory;
  207. //
  208. // Structures that store thread statistics.
  209. //
  210. PPROFILER_BUFFER *SpThreadStatisticsArray;
  211. ULONG SpThreadStatisticsArraySize;
  212. PSP_COLLECT_THREAD_STATISTIC SpCollectThreadStatisticRoutine;
  213. PSP_PROCESS_NEW_PROCESS SpProcessNewProcessRoutine;
  214. PSP_PROCESS_NEW_THREAD SpProcessNewThreadRoutine;
  215. //
  216. // ------------------------------------------------------------------ Functions
  217. //
  218. VOID
  219. SpProfilerInterrupt (
  220. PTRAP_FRAME TrapFrame
  221. )
  222. /*++
  223. Routine Description:
  224. This routine handles periodic profiler interrupts, collecting information
  225. about the system for analysis.
  226. Arguments:
  227. TrapFrame - Supplies a pointer to the current trap frame.
  228. Return Value:
  229. None.
  230. --*/
  231. {
  232. PVOID *CallStack;
  233. ULONG CallStackSize;
  234. ULONG Processor;
  235. PVOID Scratch;
  236. KSTATUS Status;
  237. ASSERT(KeGetRunLevel() == RunLevelHigh);
  238. //
  239. // Immediately return if stack sampling is not enabled. It may have been
  240. // turned off while this interrupt was pending.
  241. //
  242. if ((SpEnabledFlags & PROFILER_TYPE_FLAG_STACK_SAMPLING) == 0) {
  243. return;
  244. }
  245. //
  246. // Do nothing on interrupt replay if the trap frame is NULL.
  247. //
  248. if (TrapFrame == NULL) {
  249. return;
  250. }
  251. //
  252. // Do not collect data on processors that have not been initialized for
  253. // profiling.
  254. //
  255. Processor = KeGetCurrentProcessorNumber();
  256. if (Processor >= SpStackSamplingArraySize) {
  257. return;
  258. }
  259. //
  260. // Collect the stack data from the trap frame.
  261. //
  262. Scratch = SpStackSamplingArray[Processor]->Scratch;
  263. CallStackSize = SCRATCH_BUFFER_LENGTH - sizeof(UINTN);
  264. CallStack = (PVOID *)(Scratch + sizeof(UINTN));
  265. Status = SppArchGetKernelStackData(TrapFrame, CallStack, &CallStackSize);
  266. if (!KSUCCESS(Status)) {
  267. return;
  268. }
  269. ASSERT(CallStackSize != 0);
  270. CallStackSize += sizeof(UINTN);
  271. *((PUINTN)Scratch) = PROFILER_DATA_SENTINEL | CallStackSize;
  272. //
  273. // Write the data to the sampling buffer.
  274. //
  275. SppWriteProfilerBuffer(SpStackSamplingArray[Processor],
  276. (BYTE *)Scratch,
  277. CallStackSize);
  278. return;
  279. }
  280. VOID
  281. SpSendProfilingData (
  282. VOID
  283. )
  284. /*++
  285. Routine Description:
  286. This routine sends profiling data to any listening consumer. It is called
  287. periodically on each processor during the clock interrupt.
  288. Arguments:
  289. None.
  290. Return Value:
  291. None.
  292. --*/
  293. {
  294. ASSERT(KeGetRunLevel() >= RunLevelClock);
  295. //
  296. // Call out to the current profiling consumer to have that component ask
  297. // for the data.
  298. //
  299. KdSendProfilingData();
  300. return;
  301. }
  302. KSTATUS
  303. SpGetProfilerData (
  304. PPROFILER_NOTIFICATION ProfilerNotification,
  305. PULONG Flags
  306. )
  307. /*++
  308. Routine Description:
  309. This routine fills the provided profiler notification with profiling data.
  310. A profiler consumer should call this routine to obtain data to send over
  311. the wire. It is assumed here that consumers will serialize consumption.
  312. Arguments:
  313. ProfilerNotification - Supplies a pointer to the profiler notification that
  314. is to be filled in with profiling data.
  315. Flags - Supplies a pointer to the types of profiling data the caller wants
  316. to collect. Upon return, the flags for the returned data will be
  317. returned.
  318. Return Value:
  319. Status code.
  320. --*/
  321. {
  322. ULONG DataSize;
  323. PMEMORY_BUFFER MemoryBuffer;
  324. ULONG Processor;
  325. BOOL ReadMore;
  326. ULONG RemainingLength;
  327. ASSERT(Flags != NULL);
  328. ASSERT(*Flags != 0);
  329. //
  330. // Process the requested profiling data in a set order, removing each type
  331. // from the set of flags as it is processed.
  332. //
  333. if ((*Flags & PROFILER_TYPE_FLAG_STACK_SAMPLING) != 0) {
  334. Processor = KeGetCurrentProcessorNumber();
  335. ASSERT(Processor < SpStackSamplingArraySize);
  336. //
  337. // Fill the buffer with data from the current processor's stack
  338. // sampling data.
  339. //
  340. ReadMore = SppReadProfilerBuffer(
  341. SpStackSamplingArray[Processor],
  342. ProfilerNotification->Data,
  343. &ProfilerNotification->Header.DataSize);
  344. ProfilerNotification->Header.Type = ProfilerDataTypeStack;
  345. ProfilerNotification->Header.Processor = Processor;
  346. //
  347. // If no more data is available, it means that the consumer has read up
  348. // to the producer, or up to its stop point (the point the producer was
  349. // at when the consumer started).
  350. //
  351. if (ReadMore == FALSE) {
  352. *Flags &= ~PROFILER_TYPE_FLAG_STACK_SAMPLING;
  353. }
  354. } else if ((*Flags & PROFILER_TYPE_FLAG_MEMORY_STATISTICS) != 0) {
  355. //
  356. // If the consumer is not currently active, then get the next buffer to
  357. // consume, which is indicated by the ready index.
  358. //
  359. if (SpMemory->ConsumerActive == FALSE) {
  360. SpMemory->ConsumerIndex = SpMemory->ReadyIndex;
  361. SpMemory->ConsumerActive = TRUE;
  362. }
  363. //
  364. // Copy as much data as possible from the consumer buffer to the
  365. // profiler notification data buffer.
  366. //
  367. MemoryBuffer = &(SpMemory->MemoryBuffers[SpMemory->ConsumerIndex]);
  368. RemainingLength = MemoryBuffer->BufferSize -
  369. MemoryBuffer->ConsumerIndex;
  370. if (RemainingLength < ProfilerNotification->Header.DataSize) {
  371. DataSize = RemainingLength;
  372. } else {
  373. DataSize = ProfilerNotification->Header.DataSize;
  374. }
  375. if (DataSize != 0) {
  376. RtlCopyMemory(ProfilerNotification->Data,
  377. &(MemoryBuffer->Buffer[MemoryBuffer->ConsumerIndex]),
  378. DataSize);
  379. }
  380. MemoryBuffer->ConsumerIndex += DataSize;
  381. ProfilerNotification->Header.Type = ProfilerDataTypeMemory;
  382. ProfilerNotification->Header.Processor = KeGetCurrentProcessorNumber();
  383. ProfilerNotification->Header.DataSize = DataSize;
  384. //
  385. // Mark the consumer inactive if all the data was consumed.
  386. //
  387. if (MemoryBuffer->ConsumerIndex == MemoryBuffer->BufferSize) {
  388. SpMemory->ConsumerActive = FALSE;
  389. *Flags &= ~PROFILER_TYPE_FLAG_MEMORY_STATISTICS;
  390. }
  391. } else if ((*Flags & PROFILER_TYPE_FLAG_THREAD_STATISTICS) != 0) {
  392. Processor = KeGetCurrentProcessorNumber();
  393. ASSERT(Processor < SpThreadStatisticsArraySize);
  394. //
  395. // Fill the buffer with data from the current processor's stack
  396. // sampling data.
  397. //
  398. ReadMore = SppReadProfilerBuffer(
  399. SpThreadStatisticsArray[Processor],
  400. ProfilerNotification->Data,
  401. &(ProfilerNotification->Header.DataSize));
  402. ProfilerNotification->Header.Type = ProfilerDataTypeThread;
  403. ProfilerNotification->Header.Processor = Processor;
  404. //
  405. // If no more data is available, it means that the consumer has read up
  406. // to the producer, or up to its stop point (the point the producer was
  407. // at when the consumer started).
  408. //
  409. if (ReadMore == FALSE) {
  410. *Flags &= ~PROFILER_TYPE_FLAG_THREAD_STATISTICS;
  411. }
  412. }
  413. return STATUS_SUCCESS;
  414. }
  415. ULONG
  416. SpGetProfilerDataStatus (
  417. VOID
  418. )
  419. /*++
  420. Routine Description:
  421. This routine determines if there is profiling data for the current
  422. processor that needs to be sent to a consumer.
  423. Arguments:
  424. None.
  425. Return Value:
  426. Returns a set of flags representing which types of profiling data are
  427. available. Returns zero if nothing is available.
  428. --*/
  429. {
  430. PPROFILER_BUFFER Buffer;
  431. ULONG Flags;
  432. ULONG Processor;
  433. ASSERT(KeGetRunLevel() >= RunLevelClock);
  434. if (SpEnabledFlags == 0) {
  435. return 0;
  436. }
  437. Flags = SpEnabledFlags;
  438. //
  439. // Determine if there is stack sampling data to send.
  440. //
  441. if ((Flags & PROFILER_TYPE_FLAG_STACK_SAMPLING) != 0) {
  442. //
  443. // If stack sampling is not yet initialized on this processor remove it
  444. // from the flags.
  445. //
  446. Processor = KeGetCurrentProcessorNumber();
  447. if (Processor >= SpStackSamplingArraySize) {
  448. Flags &= ~PROFILER_TYPE_FLAG_STACK_SAMPLING;
  449. //
  450. // Otherwise if the stack sampling buffer is empty, then remove it from
  451. // the flags.
  452. //
  453. // N.B. This access if safe because the stack sampling destruction code
  454. // waits for least one clock interrupt after disabling stack
  455. // sampling before destroying the global array.
  456. //
  457. } else {
  458. Buffer = SpStackSamplingArray[Processor];
  459. if (Buffer->ProducerIndex == Buffer->ConsumerIndex) {
  460. Flags &= ~PROFILER_TYPE_FLAG_STACK_SAMPLING;
  461. }
  462. }
  463. }
  464. //
  465. // Determine if there are memory statistics to send.
  466. //
  467. if ((Flags & PROFILER_TYPE_FLAG_MEMORY_STATISTICS) != 0) {
  468. //
  469. // There is no new data if the consumer index still equals the ready
  470. // index or the producer index.
  471. //
  472. if ((SpMemory->ConsumerIndex == SpMemory->ReadyIndex) ||
  473. (SpMemory->ConsumerIndex == SpMemory->ProducerIndex)) {
  474. Flags &= ~PROFILER_TYPE_FLAG_MEMORY_STATISTICS;
  475. }
  476. }
  477. if ((Flags & PROFILER_TYPE_FLAG_THREAD_STATISTICS) != 0) {
  478. //
  479. // If thread statistics are not yet initialized on this processor
  480. // remove them from the flags.
  481. //
  482. Processor = KeGetCurrentProcessorNumber();
  483. if (Processor >= SpThreadStatisticsArraySize) {
  484. Flags &= ~PROFILER_TYPE_FLAG_THREAD_STATISTICS;
  485. //
  486. // Otherwise if the thread statistics buffer is empty, then remove it
  487. // from the flags.
  488. //
  489. // N.B. This access if safe because the thread statistics destruction
  490. // code waits for least one clock interrupt after disabling
  491. // profiling before destroying the global array.
  492. //
  493. } else {
  494. Buffer = SpThreadStatisticsArray[Processor];
  495. if (Buffer->ProducerIndex == Buffer->ConsumerIndex) {
  496. Flags &= ~PROFILER_TYPE_FLAG_THREAD_STATISTICS;
  497. }
  498. }
  499. }
  500. return Flags;
  501. }
  502. KSTATUS
  503. SpInitializeProfiler (
  504. VOID
  505. )
  506. /*++
  507. Routine Description:
  508. This routine initializes system profiling at processor start-up. It
  509. extends the profiling infrastructure as each processor comes online. If
  510. early profiling is not enabled, this routine just exits.
  511. Arguments:
  512. None.
  513. Return Value:
  514. Status code.
  515. --*/
  516. {
  517. KSTATUS Status;
  518. ASSERT(KeGetRunLevel() <= RunLevelDispatch);
  519. ASSERT(KeGetCurrentProcessorNumber() == 0);
  520. //
  521. // Always initialize the profiling lock in case profiling gets enabled
  522. // later on.
  523. //
  524. SpProfilingQueuedLock = KeCreateQueuedLock();
  525. if (SpProfilingQueuedLock == NULL) {
  526. Status = STATUS_INSUFFICIENT_RESOURCES;
  527. goto InitializeProfilerEnd;
  528. }
  529. //
  530. // Do nothing more if early profiling is not enabled for any profiling
  531. // types.
  532. //
  533. if (SpEarlyEnabledFlags != 0) {
  534. KeAcquireQueuedLock(SpProfilingQueuedLock);
  535. Status = SppStartSystemProfiler(SpEarlyEnabledFlags);
  536. KeReleaseQueuedLock(SpProfilingQueuedLock);
  537. if (!KSUCCESS(Status)) {
  538. goto InitializeProfilerEnd;
  539. }
  540. }
  541. Status = STATUS_SUCCESS;
  542. InitializeProfilerEnd:
  543. return Status;
  544. }
  545. KSTATUS
  546. SppStartSystemProfiler (
  547. ULONG Flags
  548. )
  549. /*++
  550. Routine Description:
  551. This routine starts the system profiler. This routine must be called at low
  552. level. It assumes the profiler queued lock is held.
  553. Arguments:
  554. Flags - Supplies a set of flags representing the types of profiling that
  555. should be started.
  556. Return Value:
  557. Status code.
  558. --*/
  559. {
  560. ULONG InitializedFlags;
  561. ULONG NewFlags;
  562. KSTATUS Status;
  563. ASSERT(KeGetRunLevel() == RunLevelLow);
  564. ASSERT(KeIsQueuedLockHeld(SpProfilingQueuedLock) != FALSE);
  565. //
  566. // The caller must specify flags.
  567. //
  568. if (Flags == 0) {
  569. return STATUS_INVALID_PARAMETER;
  570. }
  571. InitializedFlags = 0;
  572. //
  573. // Determine what new profiling types need to be started.
  574. //
  575. NewFlags = Flags & ~SpEnabledFlags;
  576. //
  577. // If all the desired profiling types are already active, then just exit.
  578. //
  579. if (NewFlags == 0) {
  580. Status = STATUS_SUCCESS;
  581. goto StartSystemProfilerEnd;
  582. }
  583. //
  584. // Initialize the system profiler for each of the new types.
  585. //
  586. if ((NewFlags & PROFILER_TYPE_FLAG_STACK_SAMPLING) != 0) {
  587. Status = SppInitializeStackSampling();
  588. if (!KSUCCESS(Status)) {
  589. goto StartSystemProfilerEnd;
  590. }
  591. InitializedFlags |= PROFILER_TYPE_FLAG_STACK_SAMPLING;
  592. }
  593. if ((NewFlags & PROFILER_TYPE_FLAG_MEMORY_STATISTICS) != 0) {
  594. Status = SppInitializeMemoryStatistics();
  595. if (!KSUCCESS(Status)) {
  596. goto StartSystemProfilerEnd;
  597. }
  598. InitializedFlags |= PROFILER_TYPE_FLAG_MEMORY_STATISTICS;
  599. }
  600. if ((NewFlags & PROFILER_TYPE_FLAG_THREAD_STATISTICS) != 0) {
  601. Status = SppInitializeThreadStatistics();
  602. if (!KSUCCESS(Status)) {
  603. goto StartSystemProfilerEnd;
  604. }
  605. InitializedFlags |= PROFILER_TYPE_FLAG_THREAD_STATISTICS;
  606. }
  607. KeUpdateClockForProfiling(TRUE);
  608. Status = STATUS_SUCCESS;
  609. StartSystemProfilerEnd:
  610. if (!KSUCCESS(Status)) {
  611. if (InitializedFlags != 0) {
  612. SppStopSystemProfiler(InitializedFlags);
  613. }
  614. }
  615. return Status;
  616. }
  617. KSTATUS
  618. SppStopSystemProfiler (
  619. ULONG Flags
  620. )
  621. /*++
  622. Routine Description:
  623. This routine stops the system profiler and destroys the profiling data
  624. structures. This routine must be called at low level. It assumes the
  625. profiler queued lock is held.
  626. Arguments:
  627. Flags - Supplies a set of flags representing the types of profiling that
  628. should be stopped.
  629. Return Value:
  630. Status code.
  631. --*/
  632. {
  633. BOOL DelayRequired;
  634. ULONG DisableFlags;
  635. ULONG Index;
  636. ULONG *InterruptCounts;
  637. RUNLEVEL OldRunLevel;
  638. ULONG ProcessorCount;
  639. PROCESSOR_SET Processors;
  640. KSTATUS Status;
  641. ASSERT(KeGetRunLevel() == RunLevelLow);
  642. ASSERT(KeIsQueuedLockHeld(SpProfilingQueuedLock) != FALSE);
  643. //
  644. // The caller must specify flags.
  645. //
  646. if (Flags == 0) {
  647. return STATUS_INVALID_PARAMETER;
  648. }
  649. //
  650. // Determine what profiling types need to be stopped.
  651. //
  652. DisableFlags = Flags & SpEnabledFlags;
  653. //
  654. // If profiling is already disabled for the requested profiling types, then
  655. // just exit.
  656. //
  657. if (DisableFlags == 0) {
  658. Status = STATUS_SUCCESS;
  659. goto StopSystemProfilerEnd;
  660. }
  661. //
  662. // Phase 0 destroy stops the system profiler for each type that needs to be
  663. // stopped.
  664. //
  665. if ((DisableFlags & PROFILER_TYPE_FLAG_STACK_SAMPLING) != 0) {
  666. SppDestroyStackSampling(0);
  667. }
  668. if ((DisableFlags & PROFILER_TYPE_FLAG_MEMORY_STATISTICS) != 0) {
  669. SppDestroyMemoryStatistics(0);
  670. }
  671. if ((DisableFlags & PROFILER_TYPE_FLAG_THREAD_STATISTICS) != 0) {
  672. SppDestroyThreadStatistics(0);
  673. }
  674. //
  675. // Once phase zero destruction is complete, each profiler has stopped
  676. // producing data immediately, but another core may be in the middle of
  677. // consuming profiling data during its clock interrupt. Wait until each
  678. // processor has received the notice that profiling is now disabled and
  679. // then destroy each profiler's data structures. This is guaranteed after
  680. // the clock interrupt has incremented once. If an array cannot be
  681. // allocated for the processor counts, then just yield for a bit. It is not
  682. // good enough to just send an IPI-level interrupt to each core. This may
  683. // land on top of a clock interrupt in the middle of checking to see if
  684. // there is pending profiling data, which is not done with interrupts
  685. // disabled (i.e. the IPI-level interrupt running doesn't indicate the
  686. // other core is done with the data). As a result, this routine could run
  687. // through and release the buffers being observed by the other core.
  688. //
  689. ProcessorCount = KeGetActiveProcessorCount();
  690. if (ProcessorCount > 1) {
  691. DelayRequired = TRUE;
  692. InterruptCounts = MmAllocateNonPagedPool(ProcessorCount * sizeof(ULONG),
  693. SP_ALLOCATION_TAG);
  694. if (InterruptCounts != NULL) {
  695. for (Index = 0; Index < ProcessorCount; Index += 1) {
  696. InterruptCounts[Index] = KeGetClockInterruptCount(Index);
  697. }
  698. //
  699. // As some cores may have gone idle, send a clock IPI out to all of
  700. // them to make sure the interrupt count gets incremented.
  701. //
  702. Processors.Target = ProcessorTargetAll;
  703. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  704. Status = HlSendIpi(IpiTypeClock, &Processors);
  705. KeLowerRunLevel(OldRunLevel);
  706. if (KSUCCESS(Status)) {
  707. for (Index = 0; Index < ProcessorCount; Index += 1) {
  708. while (KeGetClockInterruptCount(Index) <=
  709. InterruptCounts[Index]) {
  710. KeYield();
  711. }
  712. }
  713. DelayRequired = FALSE;
  714. }
  715. MmFreeNonPagedPool(InterruptCounts);
  716. }
  717. //
  718. // If the allocation or IPI failed above, wait a conservative second to
  719. // make sure all the cores are done consuming the profiler data.
  720. //
  721. if (DelayRequired != FALSE) {
  722. KeDelayExecution(FALSE, FALSE, MICROSECONDS_PER_SECOND);
  723. }
  724. }
  725. //
  726. // Phase 1 destroy releases any resources for each type of profiling that
  727. // was stopped in phase 0.
  728. //
  729. if ((DisableFlags & PROFILER_TYPE_FLAG_STACK_SAMPLING) != 0) {
  730. SppDestroyStackSampling(1);
  731. }
  732. if ((DisableFlags & PROFILER_TYPE_FLAG_MEMORY_STATISTICS) != 0) {
  733. SppDestroyMemoryStatistics(1);
  734. }
  735. if ((DisableFlags & PROFILER_TYPE_FLAG_THREAD_STATISTICS) != 0) {
  736. SppDestroyThreadStatistics(1);
  737. }
  738. if (SpEnabledFlags == 0) {
  739. KeUpdateClockForProfiling(FALSE);
  740. }
  741. Status = STATUS_SUCCESS;
  742. StopSystemProfilerEnd:
  743. return Status;
  744. }
  745. //
  746. // --------------------------------------------------------- Internal Functions
  747. //
  748. BOOL
  749. SppWriteProfilerBuffer (
  750. PPROFILER_BUFFER ProfilerBuffer,
  751. BYTE *Data,
  752. ULONG DataLength
  753. )
  754. /*++
  755. Routine Description:
  756. This routine writes the supplied data to the profiler data buffer. If there
  757. is not enough room in the buffer, it just exits.
  758. Arguments:
  759. ProfilerBuffer - Supplies a pointer to a profiler data buffer to which the
  760. given data should be written.
  761. Data - Supplies an array of bytes to write to the profiler data buffer.
  762. DataLength - Supplies the length of the data array, in bytes.
  763. Return Value:
  764. TRUE if the data was successfully added to the buffer.
  765. FALSE if the data was dropped.
  766. --*/
  767. {
  768. ULONG AvailableLength;
  769. ULONG BufferIndex;
  770. ULONG ConsumerIndex;
  771. ULONG DataIndex;
  772. ULONG FirstWriteLength;
  773. ULONG ProducerIndex;
  774. BOOL Result;
  775. ULONG SecondWriteLength;
  776. ULONG WriteLength;
  777. ConsumerIndex = ProfilerBuffer->ConsumerIndex;
  778. ProducerIndex = ProfilerBuffer->ProducerIndex;
  779. //
  780. // If the producer's and consumer's indices are equal, then the buffer is
  781. // empty. Allow the producer to write up until the end of the buffer, being
  782. // careful to never completely fill the buffer to differentiate between an
  783. // empty buffer and a full buffer.
  784. //
  785. if (ProducerIndex == ConsumerIndex) {
  786. AvailableLength = PROFILER_BUFFER_LENGTH - 1;
  787. //
  788. // If the producer's index is greater than the consumer's, then two writes
  789. // may be necessary to fill the buffer. Account for wrapping when
  790. // calculating the available length.
  791. //
  792. } else if (ProducerIndex > ConsumerIndex) {
  793. AvailableLength = PROFILER_BUFFER_LENGTH - ProducerIndex;
  794. AvailableLength += (ConsumerIndex - 1);
  795. //
  796. // If the producer's index is less than the consumer's, then allow the
  797. // producer to write up until 1 less than the consumer's index.
  798. //
  799. } else {
  800. ASSERT(ProducerIndex < ConsumerIndex);
  801. AvailableLength = (ConsumerIndex - 1) - ProducerIndex;
  802. }
  803. //
  804. // If the available length is not enough for the data, exit.
  805. //
  806. if (AvailableLength < DataLength) {
  807. Result = FALSE;
  808. goto WriteProfilerBufferEnd;
  809. }
  810. //
  811. // Determine if the write needs to be broken into two operations.
  812. //
  813. if ((ProducerIndex + DataLength) > PROFILER_BUFFER_LENGTH) {
  814. FirstWriteLength = PROFILER_BUFFER_LENGTH - ProducerIndex;
  815. ASSERT(FirstWriteLength <= DataLength);
  816. SecondWriteLength = DataLength - FirstWriteLength;
  817. } else {
  818. FirstWriteLength = DataLength;
  819. SecondWriteLength = 0;
  820. }
  821. //
  822. // Write the data to the buffer.
  823. //
  824. DataIndex = 0;
  825. BufferIndex = ProducerIndex;
  826. WriteLength = FirstWriteLength;
  827. RtlCopyMemory(&(ProfilerBuffer->Buffer[BufferIndex]),
  828. &(Data[DataIndex]),
  829. WriteLength);
  830. if (SecondWriteLength != 0) {
  831. DataIndex = WriteLength;
  832. BufferIndex = 0;
  833. WriteLength = SecondWriteLength;
  834. RtlCopyMemory(&(ProfilerBuffer->Buffer[BufferIndex]),
  835. &(Data[DataIndex]),
  836. WriteLength);
  837. }
  838. //
  839. // Update the producer index.
  840. //
  841. ProducerIndex = BufferIndex + WriteLength;
  842. if (ProducerIndex == PROFILER_BUFFER_LENGTH) {
  843. ProfilerBuffer->ProducerIndex = 0;
  844. } else {
  845. ProfilerBuffer->ProducerIndex = ProducerIndex;
  846. }
  847. Result = TRUE;
  848. WriteProfilerBufferEnd:
  849. return Result;
  850. }
  851. BOOL
  852. SppReadProfilerBuffer (
  853. PPROFILER_BUFFER ProfilerBuffer,
  854. BYTE *Data,
  855. PULONG DataLength
  856. )
  857. /*++
  858. Routine Description:
  859. This routine reads up to the provided data length of bytes from the given
  860. profiler buffer. Upon return, the data length is modified to reflect the
  861. total number of bytes read. If there are no new bytes to read from the
  862. buffer, then a data length of zero is returned.
  863. Arguments:
  864. ProfilerBuffer - Supplies a pointer to a profiler data buffer from which
  865. up to data length bytes will be read.
  866. Data - Supplies an array of bytes that is to receive data from the profiler
  867. buffer.
  868. DataLength - Supplies the maximum number of bytes that can be read into the
  869. data buffer. Receives the total bytes read upon return.
  870. Return Value:
  871. Returns TRUE if there is more data to be read, or FALSE otherwise..
  872. --*/
  873. {
  874. ULONG AvailableLength;
  875. ULONG BytesRead;
  876. ULONG ConsumerIndex;
  877. ULONG ConsumerStopIndex;
  878. ULONG FirstReadLength;
  879. BOOL MoreDataAvailable;
  880. ULONG ProducerIndex;
  881. ULONG RemainingLength;
  882. ULONG SecondReadLength;
  883. ULONG TotalReadLength;
  884. ASSERT(ProfilerBuffer != NULL);
  885. ASSERT(Data != NULL);
  886. ASSERT(DataLength != NULL);
  887. ConsumerIndex = ProfilerBuffer->ConsumerIndex;
  888. ProducerIndex = ProfilerBuffer->ProducerIndex;
  889. ConsumerStopIndex = ProfilerBuffer->ConsumerStopIndex;
  890. SecondReadLength = 0;
  891. AvailableLength = *DataLength;
  892. *DataLength = 0;
  893. MoreDataAvailable = FALSE;
  894. //
  895. // If the stop index equals the consumer index, then advance it to
  896. // the producer index in order to gather all of the currently available
  897. // data. Do this so that the consumer will eventually complete when faced
  898. // with a speedy producer.
  899. //
  900. if (ConsumerIndex == ConsumerStopIndex) {
  901. ProfilerBuffer->ConsumerStopIndex = ProducerIndex;
  902. }
  903. //
  904. // If the producer's and consumer's indices are equal, then there are no
  905. // bytes to consume. The buffer is empty.
  906. //
  907. if (ProducerIndex == ConsumerIndex) {
  908. goto EmptyProfilerBufferEnd;
  909. //
  910. // If the producer is ahead of the consumer, then consume the buffer all
  911. // the way up to the producer's index or up to the provided buffer size.
  912. //
  913. } else if (ProducerIndex > ConsumerIndex) {
  914. FirstReadLength = ProducerIndex - ConsumerIndex;
  915. if (FirstReadLength > AvailableLength) {
  916. FirstReadLength = AvailableLength;
  917. }
  918. //
  919. // If the producer is behind the consumer, then two reads are required to
  920. // wrap around the circular buffer. Truncate based on the provided data
  921. // length.
  922. //
  923. } else {
  924. ASSERT(ProducerIndex < ConsumerIndex);
  925. FirstReadLength = PROFILER_BUFFER_LENGTH - ConsumerIndex;
  926. if (FirstReadLength > AvailableLength) {
  927. FirstReadLength = AvailableLength;
  928. } else {
  929. SecondReadLength = ProducerIndex;
  930. if ((FirstReadLength + SecondReadLength) > AvailableLength) {
  931. SecondReadLength = AvailableLength - FirstReadLength;
  932. }
  933. }
  934. }
  935. TotalReadLength = FirstReadLength + SecondReadLength;
  936. //
  937. // The provided data buffer should be large enough to fit the determined
  938. // reads.
  939. //
  940. ASSERT(AvailableLength >= TotalReadLength);
  941. //
  942. // Read the data out into the supplied buffer, making sure to read on the
  943. // profiler unit boundary, as marked by the sentinel.
  944. //
  945. RemainingLength = TotalReadLength;
  946. BytesRead = SppReadProfilerData(&(Data[0]),
  947. &(ProfilerBuffer->Buffer[ConsumerIndex]),
  948. FirstReadLength,
  949. &RemainingLength);
  950. if ((SecondReadLength != 0) && (BytesRead == FirstReadLength)) {
  951. ASSERT(RemainingLength == SecondReadLength);
  952. BytesRead = SppReadProfilerData(&(Data[FirstReadLength]),
  953. &(ProfilerBuffer->Buffer[0]),
  954. SecondReadLength,
  955. &RemainingLength);
  956. ASSERT(SecondReadLength == (BytesRead + RemainingLength));
  957. ConsumerIndex = BytesRead;
  958. } else {
  959. ConsumerIndex += BytesRead;
  960. }
  961. //
  962. // Update the data length based on how much data was read.
  963. //
  964. *DataLength = TotalReadLength - RemainingLength;
  965. //
  966. // Update the consumer index.
  967. //
  968. if (ConsumerIndex == PROFILER_BUFFER_LENGTH) {
  969. ProfilerBuffer->ConsumerIndex = 0;
  970. } else {
  971. ProfilerBuffer->ConsumerIndex = ConsumerIndex;
  972. }
  973. //
  974. // If the stop index has been reached with this read, let the caller know
  975. // that there is no more data to collect at this time.
  976. //
  977. if (ProfilerBuffer->ConsumerIndex != ProfilerBuffer->ConsumerStopIndex) {
  978. MoreDataAvailable = TRUE;
  979. }
  980. EmptyProfilerBufferEnd:
  981. return MoreDataAvailable;
  982. }
  983. ULONG
  984. SppReadProfilerData (
  985. BYTE *Destination,
  986. BYTE *Source,
  987. ULONG ByteCount,
  988. PULONG BytesRemaining
  989. )
  990. /*++
  991. Routine Description:
  992. This routine reads as many profiler data units as it can, up to the
  993. supplied byte count, making sure to never exceed the remaining available
  994. bytes.
  995. Arguments:
  996. Destination - Supplies a pointer to the destination data buffer.
  997. Source - Supplies a pointer to the source data buffer.
  998. ByteCount - Supplies the maximum number of bytes that should be read out of
  999. the source buffer.
  1000. BytesRemaining - Supplies a pointer to the maximum number of bytes that
  1001. can be read to the destination buffer. It is updated upon return.
  1002. Return Value:
  1003. Returns the number of bytes read by this routine.
  1004. --*/
  1005. {
  1006. ULONG BytesRead;
  1007. ULONG DestinationIndex;
  1008. ULONG SourceIndex;
  1009. ULONG Value;
  1010. BytesRead = 0;
  1011. DestinationIndex = 0;
  1012. for (SourceIndex = 0; SourceIndex < ByteCount; SourceIndex += 1) {
  1013. //
  1014. // If the current byte is the start of the sentinel, check the length
  1015. // of the next data packet and do not continue if it will not fit in
  1016. // the destination buffer.
  1017. //
  1018. Value = *((PULONG)&(Source[SourceIndex]));
  1019. if (IS_PROFILER_DATA_SENTINEL(Value) != FALSE) {
  1020. if (GET_PROFILER_DATA_SIZE(Value) > *BytesRemaining) {
  1021. break;
  1022. }
  1023. }
  1024. Destination[DestinationIndex] = Source[SourceIndex];
  1025. DestinationIndex += 1;
  1026. *BytesRemaining -= 1;
  1027. BytesRead += 1;
  1028. }
  1029. return BytesRead;
  1030. }
  1031. KSTATUS
  1032. SppInitializeStackSampling (
  1033. VOID
  1034. )
  1035. /*++
  1036. Routine Description:
  1037. This routine initializes the system's profiling data structures.
  1038. Arguments:
  1039. None.
  1040. Return Value:
  1041. Status code.
  1042. --*/
  1043. {
  1044. ULONG AllocationSize;
  1045. ULONG Index;
  1046. ULONG ProcessorCount;
  1047. PPROFILER_BUFFER ProfilerBuffer;
  1048. PPROFILER_BUFFER *StackSamplingArray;
  1049. KSTATUS Status;
  1050. ASSERT(KeGetRunLevel() == RunLevelLow);
  1051. ASSERT((SpEnabledFlags & PROFILER_TYPE_FLAG_STACK_SAMPLING) == 0);
  1052. ASSERT(KeIsQueuedLockHeld(SpProfilingQueuedLock) != FALSE);
  1053. ASSERT(SpStackSamplingArray == NULL);
  1054. ASSERT(SpStackSamplingArraySize == 0);
  1055. ProcessorCount = KeGetActiveProcessorCount();
  1056. AllocationSize = ProcessorCount * sizeof(PPROFILER_BUFFER);
  1057. StackSamplingArray = MmAllocateNonPagedPool(AllocationSize,
  1058. SP_ALLOCATION_TAG);
  1059. if (StackSamplingArray == NULL) {
  1060. Status = STATUS_INSUFFICIENT_RESOURCES;
  1061. goto InitializeProfilerEnd;
  1062. }
  1063. //
  1064. // Now fill in the array with profiler buffers.
  1065. //
  1066. RtlZeroMemory(StackSamplingArray, AllocationSize);
  1067. for (Index = 0; Index < ProcessorCount; Index += 1) {
  1068. ProfilerBuffer = MmAllocateNonPagedPool(sizeof(PROFILER_BUFFER),
  1069. SP_ALLOCATION_TAG);
  1070. if (ProfilerBuffer == NULL) {
  1071. Status = STATUS_INSUFFICIENT_RESOURCES;
  1072. goto InitializeProfilerEnd;
  1073. }
  1074. RtlZeroMemory(ProfilerBuffer, sizeof(PROFILER_BUFFER));
  1075. StackSamplingArray[Index] = ProfilerBuffer;
  1076. }
  1077. //
  1078. // Start the timer and then mark the profiler as enabled and update the
  1079. // stack sampling globals. This might cause some initial interrupts to skip
  1080. // data collection, but that's OK.
  1081. //
  1082. Status = HlStartProfilerTimer();
  1083. if (!KSUCCESS(Status)) {
  1084. goto InitializeProfilerEnd;
  1085. }
  1086. SpStackSamplingArray = StackSamplingArray;
  1087. SpStackSamplingArraySize = ProcessorCount;
  1088. RtlMemoryBarrier();
  1089. SpEnabledFlags |= PROFILER_TYPE_FLAG_STACK_SAMPLING;
  1090. InitializeProfilerEnd:
  1091. if (!KSUCCESS(Status)) {
  1092. for (Index = 0; Index < ProcessorCount; Index += 1) {
  1093. if (StackSamplingArray[Index] != NULL) {
  1094. MmFreeNonPagedPool(StackSamplingArray[Index]);
  1095. }
  1096. }
  1097. MmFreeNonPagedPool(StackSamplingArray);
  1098. }
  1099. return Status;
  1100. }
  1101. VOID
  1102. SppDestroyStackSampling (
  1103. ULONG Phase
  1104. )
  1105. /*++
  1106. Routine Description:
  1107. This routine tears down stack sampling by disabling the profiler timer and
  1108. destroy the stack sampling data structures. Phase 0 stops the stack
  1109. sampling profiler producers and consumers. Phase 1 cleans up resources.
  1110. Arguments:
  1111. Phase - Supplies the current phase of the destruction process.
  1112. Return Value:
  1113. None.
  1114. --*/
  1115. {
  1116. ULONG Index;
  1117. ASSERT(KeGetRunLevel() == RunLevelLow);
  1118. ASSERT(KeIsQueuedLockHeld(SpProfilingQueuedLock) != FALSE);
  1119. ASSERT(SpStackSamplingArray != NULL);
  1120. ASSERT(SpStackSamplingArraySize != 0);
  1121. if (Phase == 0) {
  1122. ASSERT((SpEnabledFlags & PROFILER_TYPE_FLAG_STACK_SAMPLING) != 0);
  1123. //
  1124. // Disable stack sampling before disabling the profiler timer to
  1125. // prevent any pending producer interrupts from touching the buffers
  1126. // after they are released
  1127. //
  1128. SpEnabledFlags &= ~PROFILER_TYPE_FLAG_STACK_SAMPLING;
  1129. //
  1130. // Stop the profiler timer. Since the caller will wait for at least
  1131. // one more clock interrupt, it is safe to proceed even though stopping
  1132. // the timer doesn't guarantee the profiler interrupt will not run
  1133. // again. It could be pending on another processor. The wait for the
  1134. // clock interrupt will guarantee that the all high level and IPI
  1135. // interrupts have completed.
  1136. //
  1137. HlStopProfilerTimer();
  1138. } else {
  1139. ASSERT(Phase == 1);
  1140. ASSERT((SpEnabledFlags & PROFILER_TYPE_FLAG_STACK_SAMPLING) == 0);
  1141. //
  1142. // Destroy the stack sampling array.
  1143. //
  1144. for (Index = 0; Index < SpStackSamplingArraySize; Index += 1) {
  1145. if (SpStackSamplingArray[Index] != NULL) {
  1146. MmFreeNonPagedPool(SpStackSamplingArray[Index]);
  1147. }
  1148. }
  1149. MmFreeNonPagedPool(SpStackSamplingArray);
  1150. SpStackSamplingArray = NULL;
  1151. SpStackSamplingArraySize = 0;
  1152. }
  1153. return;
  1154. }
  1155. KSTATUS
  1156. SppInitializeMemoryStatistics (
  1157. VOID
  1158. )
  1159. /*++
  1160. Routine Description:
  1161. This routine initializes the structures and timers necessary for profiling
  1162. system memory statistics.
  1163. Arguments:
  1164. None.
  1165. Return Value:
  1166. Status code.
  1167. --*/
  1168. {
  1169. ULONGLONG Period;
  1170. KSTATUS Status;
  1171. ASSERT(KeGetRunLevel() == RunLevelLow);
  1172. ASSERT(KeIsQueuedLockHeld(SpProfilingQueuedLock) != FALSE);
  1173. ASSERT(SpMemory == NULL);
  1174. //
  1175. // Allocate the memory profiler structure.
  1176. //
  1177. SpMemory = MmAllocateNonPagedPool(sizeof(MEMORY_PROFILER),
  1178. SP_ALLOCATION_TAG);
  1179. if (SpMemory == NULL) {
  1180. Status = STATUS_INSUFFICIENT_RESOURCES;
  1181. goto InitializeMemoryStatisticsEnd;
  1182. }
  1183. RtlZeroMemory(SpMemory, sizeof(MEMORY_PROFILER));
  1184. ASSERT(SpMemory->ConsumerActive == FALSE);
  1185. ASSERT(SpMemory->ReadyIndex == 0);
  1186. ASSERT(SpMemory->ProducerIndex == 0);
  1187. SpMemory->ConsumerIndex = MEMORY_BUFFER_COUNT - 1;
  1188. //
  1189. // Create the timer that will periodically trigger memory statistics.
  1190. //
  1191. SpMemory->Timer = KeCreateTimer(SP_ALLOCATION_TAG);
  1192. if (SpMemory->Timer == NULL) {
  1193. Status = STATUS_INSUFFICIENT_RESOURCES;
  1194. goto InitializeMemoryStatisticsEnd;
  1195. }
  1196. //
  1197. // Queue the timer.
  1198. //
  1199. Period = KeConvertMicrosecondsToTimeTicks(MEMORY_STATISTICS_TIMER_PERIOD);
  1200. Status = KeQueueTimer(SpMemory->Timer,
  1201. TimerQueueSoft,
  1202. 0,
  1203. Period,
  1204. 0,
  1205. NULL);
  1206. if (!KSUCCESS(Status)) {
  1207. goto InitializeMemoryStatisticsEnd;
  1208. }
  1209. //
  1210. // Create the worker thread, which will wait on the timer. Add an extra
  1211. // reference because the destruction routine waits until this thread exits.
  1212. //
  1213. SpMemory->ThreadAlive = TRUE;
  1214. Status = PsCreateKernelThread(SppMemoryStatisticsThread,
  1215. NULL,
  1216. "SppMemoryStatisticsThread");
  1217. if (!KSUCCESS(Status)) {
  1218. SpMemory->ThreadAlive = FALSE;
  1219. goto InitializeMemoryStatisticsEnd;
  1220. }
  1221. //
  1222. // Make sure everything above is complete before turning this on.
  1223. //
  1224. RtlMemoryBarrier();
  1225. SpEnabledFlags |= PROFILER_TYPE_FLAG_MEMORY_STATISTICS;
  1226. InitializeMemoryStatisticsEnd:
  1227. if (!KSUCCESS(Status)) {
  1228. if (SpMemory != NULL) {
  1229. if (SpMemory->Timer != NULL) {
  1230. KeDestroyTimer(SpMemory->Timer);
  1231. }
  1232. //
  1233. // Thread creation should be the last point of failure.
  1234. //
  1235. ASSERT(SpMemory->ThreadAlive == FALSE);
  1236. MmFreeNonPagedPool(SpMemory);
  1237. SpMemory = NULL;
  1238. }
  1239. }
  1240. return Status;
  1241. }
  1242. VOID
  1243. SppDestroyMemoryStatistics (
  1244. ULONG Phase
  1245. )
  1246. /*++
  1247. Routine Description:
  1248. This routine destroys the structures and timers used to profile system
  1249. memory statistics. Phase 0 stops the memory profiler producers and
  1250. consumers. Phase 1 cleans up resources.
  1251. Arguments:
  1252. Phase - Supplies the current phase of the destruction process.
  1253. Return Value:
  1254. None.
  1255. --*/
  1256. {
  1257. ULONG Index;
  1258. KSTATUS Status;
  1259. ASSERT(KeGetRunLevel() == RunLevelLow);
  1260. ASSERT(KeIsQueuedLockHeld(SpProfilingQueuedLock) != FALSE);
  1261. ASSERT(SpMemory != NULL);
  1262. ASSERT(SpMemory->Timer != NULL);
  1263. if (Phase == 0) {
  1264. ASSERT(SpMemory->ThreadAlive != FALSE);
  1265. ASSERT((SpEnabledFlags & PROFILER_TYPE_FLAG_MEMORY_STATISTICS) != 0);
  1266. //
  1267. // Disable the memory statistics profiler.
  1268. //
  1269. SpEnabledFlags &= ~PROFILER_TYPE_FLAG_MEMORY_STATISTICS;
  1270. //
  1271. // Cancel the timer. This is a periodic timer, so cancel should always
  1272. // succeed.
  1273. //
  1274. Status = KeCancelTimer(SpMemory->Timer);
  1275. ASSERT(KSUCCESS(Status));
  1276. //
  1277. // Queue the timer one more time in case the worker thread was in the
  1278. // act of waiting when the timer was cancelled or was processing data.
  1279. //
  1280. Status = KeQueueTimer(SpMemory->Timer,
  1281. TimerQueueSoftWake,
  1282. 0,
  1283. 0,
  1284. 0,
  1285. NULL);
  1286. ASSERT(KSUCCESS(Status));
  1287. //
  1288. // Wait until the thread exits in order to be sure that it has
  1289. // registered that profiling has been cancelled.
  1290. //
  1291. while (SpMemory->ThreadAlive != FALSE) {
  1292. KeYield();
  1293. }
  1294. } else {
  1295. ASSERT(Phase == 1);
  1296. ASSERT((SpEnabledFlags & PROFILER_TYPE_FLAG_MEMORY_STATISTICS) == 0);
  1297. ASSERT(SpMemory->ThreadAlive == FALSE);
  1298. //
  1299. // Destroy the timer.
  1300. //
  1301. KeDestroyTimer(SpMemory->Timer);
  1302. //
  1303. // Release any buffers that are holding pool statistics.
  1304. //
  1305. for (Index = 0; Index < MEMORY_BUFFER_COUNT; Index += 1) {
  1306. if (SpMemory->MemoryBuffers[Index].Buffer != NULL) {
  1307. MmFreeNonPagedPool(SpMemory->MemoryBuffers[Index].Buffer);
  1308. }
  1309. }
  1310. MmFreeNonPagedPool(SpMemory);
  1311. SpMemory = NULL;
  1312. }
  1313. return;
  1314. }
  1315. VOID
  1316. SppMemoryStatisticsThread (
  1317. PVOID Parameter
  1318. )
  1319. /*++
  1320. Routine Description:
  1321. This routine is the workhorse for gathering memory statistics and writing
  1322. them to a buffer than can then be consumed on the clock interrupt. It waits
  1323. on the memory statistics timer before periodically collecting the
  1324. statistics.
  1325. Arguments:
  1326. Parameter - Supplies a pointer supplied by the creator of the thread. This
  1327. pointer is not used.
  1328. Return Value:
  1329. None.
  1330. --*/
  1331. {
  1332. PVOID Buffer;
  1333. ULONG BufferSize;
  1334. ULONG Index;
  1335. PMEMORY_BUFFER MemoryBuffer;
  1336. KSTATUS Status;
  1337. ASSERT(KeGetRunLevel() == RunLevelLow);
  1338. ASSERT(SpMemory->ThreadAlive != FALSE);
  1339. while (TRUE) {
  1340. //
  1341. // Wait for the memory statistics timer to expire.
  1342. //
  1343. ObWaitOnObject(SpMemory->Timer, 0, WAIT_TIME_INDEFINITE);
  1344. //
  1345. // Check to make sure memory statistics profiling is still enabled.
  1346. //
  1347. if ((SpEnabledFlags & PROFILER_TYPE_FLAG_MEMORY_STATISTICS) == 0) {
  1348. break;
  1349. }
  1350. //
  1351. // Call the memory manager to get the latest pool statistics. It will
  1352. // pass back an appropriately sized buffer with all the statistics.
  1353. //
  1354. Status = MmGetPoolProfilerStatistics(&Buffer,
  1355. &BufferSize,
  1356. SP_ALLOCATION_TAG);
  1357. if (!KSUCCESS(Status)) {
  1358. continue;
  1359. }
  1360. //
  1361. // Get the producer's memory buffer.
  1362. //
  1363. ASSERT(SpMemory->ProducerIndex < MEMORY_BUFFER_COUNT);
  1364. MemoryBuffer = &(SpMemory->MemoryBuffers[SpMemory->ProducerIndex]);
  1365. //
  1366. // Destroy what is currently in the memory buffer.
  1367. //
  1368. if (MemoryBuffer->Buffer != NULL) {
  1369. MmFreeNonPagedPool(MemoryBuffer->Buffer);
  1370. }
  1371. //
  1372. // Reinitialize the buffer.
  1373. //
  1374. MemoryBuffer->Buffer = Buffer;
  1375. MemoryBuffer->BufferSize = BufferSize;
  1376. MemoryBuffer->ConsumerIndex = 0;
  1377. //
  1378. // Now that this is the latest and greatest memory information, point
  1379. // the ready index at it. It doesn't matter that the ready index and
  1380. // the producer index will temporarily be the same. There is a
  1381. // guarantee that the producer will not produce again until it points
  1382. // at a new buffer. This makes it safe for the consumer to just grab
  1383. // the ready index.
  1384. //
  1385. SpMemory->ReadyIndex = SpMemory->ProducerIndex;
  1386. //
  1387. // Now search for the free buffer and make it the producer index. There
  1388. // always has to be one free.
  1389. //
  1390. for (Index = 0; Index < MEMORY_BUFFER_COUNT; Index += 1) {
  1391. if ((Index != SpMemory->ReadyIndex) &&
  1392. (Index != SpMemory->ConsumerIndex)) {
  1393. SpMemory->ProducerIndex = Index;
  1394. break;
  1395. }
  1396. }
  1397. ASSERT(SpMemory->ReadyIndex != SpMemory->ProducerIndex);
  1398. }
  1399. SpMemory->ThreadAlive = FALSE;
  1400. return;
  1401. }
  1402. KSTATUS
  1403. SppInitializeThreadStatistics (
  1404. VOID
  1405. )
  1406. /*++
  1407. Routine Description:
  1408. This routine initializes the system's thread profiling data structures.
  1409. Arguments:
  1410. None.
  1411. Return Value:
  1412. Status code.
  1413. --*/
  1414. {
  1415. ULONG AllocationSize;
  1416. ULONG Index;
  1417. RUNLEVEL OldRunLevel;
  1418. ULONG ProcessorCount;
  1419. ULONG ProcessorNumber;
  1420. PPROFILER_BUFFER ProfilerBuffer;
  1421. KSTATUS Status;
  1422. SYSTEM_TIME SystemTime;
  1423. PPROFILER_BUFFER *ThreadStatisticsArray;
  1424. PROFILER_THREAD_TIME_COUNTER TimeCounterEvent;
  1425. ASSERT(KeGetRunLevel() == RunLevelLow);
  1426. ASSERT((SpEnabledFlags & PROFILER_TYPE_FLAG_THREAD_STATISTICS) == 0);
  1427. ASSERT(KeIsQueuedLockHeld(SpProfilingQueuedLock) != FALSE);
  1428. ASSERT(SpThreadStatisticsArray == NULL);
  1429. ASSERT(SpThreadStatisticsArraySize == 0);
  1430. ProcessorCount = KeGetActiveProcessorCount();
  1431. AllocationSize = ProcessorCount * sizeof(PPROFILER_BUFFER);
  1432. ThreadStatisticsArray = MmAllocateNonPagedPool(AllocationSize,
  1433. SP_ALLOCATION_TAG);
  1434. if (ThreadStatisticsArray == NULL) {
  1435. Status = STATUS_INSUFFICIENT_RESOURCES;
  1436. goto InitializeProfilerEnd;
  1437. }
  1438. //
  1439. // Now fill in the array with profiler buffers.
  1440. //
  1441. RtlZeroMemory(ThreadStatisticsArray, AllocationSize);
  1442. for (Index = 0; Index < ProcessorCount; Index += 1) {
  1443. ProfilerBuffer = MmAllocateNonPagedPool(sizeof(PROFILER_BUFFER),
  1444. SP_ALLOCATION_TAG);
  1445. if (ProfilerBuffer == NULL) {
  1446. Status = STATUS_INSUFFICIENT_RESOURCES;
  1447. goto InitializeProfilerEnd;
  1448. }
  1449. RtlZeroMemory(ProfilerBuffer, sizeof(PROFILER_BUFFER));
  1450. ThreadStatisticsArray[Index] = ProfilerBuffer;
  1451. }
  1452. SpThreadStatisticsArray = ThreadStatisticsArray;
  1453. SpThreadStatisticsArraySize = ProcessorCount;
  1454. //
  1455. // Enable profiling by filling in the function pointer.
  1456. //
  1457. SpCollectThreadStatisticRoutine = SppCollectThreadStatistic;
  1458. SpProcessNewProcessRoutine = SppProcessNewProcess;
  1459. SpProcessNewThreadRoutine = SppProcessNewThread;
  1460. RtlMemoryBarrier();
  1461. SpEnabledFlags |= PROFILER_TYPE_FLAG_THREAD_STATISTICS;
  1462. //
  1463. // Raise to dispatch (so that no thread events are added on this processor)
  1464. // and add the first event, a time counter synchronization event.
  1465. //
  1466. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  1467. ProcessorNumber = KeGetCurrentProcessorNumber();
  1468. TimeCounterEvent.EventType = ProfilerThreadEventTimeCounter;
  1469. TimeCounterEvent.TimeCounter = HlQueryTimeCounter();
  1470. KeGetSystemTime(&SystemTime);
  1471. TimeCounterEvent.SystemTimeSeconds = SystemTime.Seconds;
  1472. TimeCounterEvent.SystemTimeNanoseconds = SystemTime.Nanoseconds;
  1473. TimeCounterEvent.TimeCounterFrequency = HlQueryTimeCounterFrequency();
  1474. SppWriteProfilerBuffer(SpThreadStatisticsArray[ProcessorNumber],
  1475. (BYTE *)&TimeCounterEvent,
  1476. sizeof(PROFILER_THREAD_TIME_COUNTER));
  1477. KeLowerRunLevel(OldRunLevel);
  1478. SppSendInitialProcesses();
  1479. Status = STATUS_SUCCESS;
  1480. InitializeProfilerEnd:
  1481. if (!KSUCCESS(Status)) {
  1482. for (Index = 0; Index < ProcessorCount; Index += 1) {
  1483. if (ThreadStatisticsArray[Index] != NULL) {
  1484. MmFreeNonPagedPool(ThreadStatisticsArray[Index]);
  1485. }
  1486. }
  1487. MmFreeNonPagedPool(ThreadStatisticsArray);
  1488. }
  1489. return Status;
  1490. }
  1491. VOID
  1492. SppSendInitialProcesses (
  1493. VOID
  1494. )
  1495. /*++
  1496. Routine Description:
  1497. This routine sends the initial set of process and threads active on the
  1498. system. This routine must be called at low level.
  1499. Arguments:
  1500. None.
  1501. Return Value:
  1502. None.
  1503. --*/
  1504. {
  1505. BOOL Added;
  1506. ULONG ConsumedSize;
  1507. PPROFILER_THREAD_NEW_PROCESS Event;
  1508. ULONG MaxNameSize;
  1509. PSTR Name;
  1510. ULONG NameSize;
  1511. RUNLEVEL OldRunLevel;
  1512. PPROCESS_INFORMATION Process;
  1513. PPROCESS_INFORMATION ProcessList;
  1514. ULONG ProcessListSize;
  1515. ULONG ProcessorNumber;
  1516. KSTATUS Status;
  1517. KSTATUS ThreadStatus;
  1518. ASSERT(KeGetRunLevel() == RunLevelLow);
  1519. ProcessList = NULL;
  1520. Status = PsGetAllProcessInformation(SP_ALLOCATION_TAG,
  1521. (PVOID)&ProcessList,
  1522. &ProcessListSize);
  1523. if (!KSUCCESS(Status)) {
  1524. goto SendInitialProcessesEnd;
  1525. }
  1526. ConsumedSize = 0;
  1527. MaxNameSize = SCRATCH_BUFFER_LENGTH -
  1528. FIELD_OFFSET(PROFILER_THREAD_NEW_PROCESS, Name);
  1529. Process = ProcessList;
  1530. while (ConsumedSize < ProcessListSize) {
  1531. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  1532. ProcessorNumber = KeGetCurrentProcessorNumber();
  1533. Event = (PVOID)(SpThreadStatisticsArray[ProcessorNumber]->Scratch);
  1534. Event->EventType = ProfilerThreadEventNewProcess;
  1535. NameSize = Process->NameLength * sizeof(CHAR);
  1536. if (NameSize > MaxNameSize) {
  1537. NameSize = MaxNameSize;
  1538. }
  1539. Event->StructureSize = sizeof(PROFILER_THREAD_NEW_PROCESS);
  1540. if (NameSize != 0) {
  1541. Event->StructureSize -= ANYSIZE_ARRAY * sizeof(CHAR);
  1542. Event->StructureSize += NameSize;
  1543. Name = (PSTR)((PVOID)Process + Process->NameOffset);
  1544. RtlStringCopy(Event->Name, Name, NameSize);
  1545. } else {
  1546. Event->Name[0] = STRING_TERMINATOR;
  1547. }
  1548. Event->ProcessId = Process->ProcessId;
  1549. Event->TimeCounter = 0;
  1550. Added = SppWriteProfilerBuffer(SpThreadStatisticsArray[ProcessorNumber],
  1551. (BYTE *)Event,
  1552. Event->StructureSize);
  1553. if (Added == FALSE) {
  1554. Status = STATUS_BUFFER_TOO_SMALL;
  1555. }
  1556. KeLowerRunLevel(OldRunLevel);
  1557. ThreadStatus = SppSendInitialThreads(Process->ProcessId);
  1558. if (!KSUCCESS(ThreadStatus)) {
  1559. Status = ThreadStatus;
  1560. }
  1561. ConsumedSize += Process->StructureSize;
  1562. ASSERT(ConsumedSize <= ProcessListSize);
  1563. Process = (PPROCESS_INFORMATION)((PUCHAR)Process +
  1564. Process->StructureSize);
  1565. }
  1566. Status = STATUS_SUCCESS;
  1567. SendInitialProcessesEnd:
  1568. if (ProcessList != NULL) {
  1569. MmFreeNonPagedPool(ProcessList);
  1570. }
  1571. if (!KSUCCESS(Status)) {
  1572. RtlDebugPrint("Profiler: Failed to send initial processes: %x.\n",
  1573. Status);
  1574. }
  1575. return;
  1576. }
  1577. KSTATUS
  1578. SppSendInitialThreads (
  1579. PROCESS_ID ProcessId
  1580. )
  1581. /*++
  1582. Routine Description:
  1583. This routine sends the initial set of threads for the given process.
  1584. This routine must be called at dispatch level.
  1585. Arguments:
  1586. ProcessId - Supplies the process ID of the threads to send.
  1587. Return Value:
  1588. None.
  1589. --*/
  1590. {
  1591. BOOL Added;
  1592. ULONG ConsumedSize;
  1593. PPROFILER_THREAD_NEW_THREAD Event;
  1594. ULONG MaxNameSize;
  1595. ULONG NameSize;
  1596. RUNLEVEL OldRunLevel;
  1597. ULONG ProcessorNumber;
  1598. KSTATUS Status;
  1599. PTHREAD_INFORMATION Thread;
  1600. PTHREAD_INFORMATION ThreadList;
  1601. ULONG ThreadListSize;
  1602. ASSERT(KeGetRunLevel() == RunLevelLow);
  1603. if ((SpEnabledFlags & PROFILER_TYPE_FLAG_THREAD_STATISTICS) == 0) {
  1604. return STATUS_SUCCESS;
  1605. }
  1606. ThreadList = NULL;
  1607. Status = PsGetThreadList(ProcessId,
  1608. SP_ALLOCATION_TAG,
  1609. (PVOID)&ThreadList,
  1610. &ThreadListSize);
  1611. if (!KSUCCESS(Status)) {
  1612. goto SendInitialThreadsEnd;
  1613. }
  1614. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  1615. ProcessorNumber = KeGetCurrentProcessorNumber();
  1616. Event = (PVOID)(SpThreadStatisticsArray[ProcessorNumber]->Scratch);
  1617. ConsumedSize = 0;
  1618. MaxNameSize = SCRATCH_BUFFER_LENGTH -
  1619. FIELD_OFFSET(PROFILER_THREAD_NEW_THREAD, Name);
  1620. Event->EventType = ProfilerThreadEventNewThread;
  1621. Thread = ThreadList;
  1622. while (ConsumedSize < ThreadListSize) {
  1623. ASSERT(Thread->StructureSize >= sizeof(THREAD_INFORMATION));
  1624. NameSize = Thread->StructureSize -
  1625. FIELD_OFFSET(THREAD_INFORMATION, Name);
  1626. if (NameSize > MaxNameSize) {
  1627. NameSize = MaxNameSize;
  1628. }
  1629. Event->StructureSize = sizeof(PROFILER_THREAD_NEW_THREAD) -
  1630. (ANYSIZE_ARRAY * sizeof(CHAR)) + NameSize;
  1631. Event->ProcessId = ProcessId;
  1632. Event->ThreadId = Thread->ThreadId;
  1633. Event->TimeCounter = 0;
  1634. RtlStringCopy(Event->Name, Thread->Name, NameSize);
  1635. Added = SppWriteProfilerBuffer(SpThreadStatisticsArray[ProcessorNumber],
  1636. (BYTE *)Event,
  1637. Event->StructureSize);
  1638. if (Added == FALSE) {
  1639. Status = STATUS_BUFFER_TOO_SMALL;
  1640. }
  1641. ConsumedSize += Thread->StructureSize;
  1642. ASSERT(ConsumedSize <= ThreadListSize);
  1643. Thread = (PTHREAD_INFORMATION)((PUCHAR)Thread + Thread->StructureSize);
  1644. }
  1645. KeLowerRunLevel(OldRunLevel);
  1646. Status = STATUS_SUCCESS;
  1647. SendInitialThreadsEnd:
  1648. if (ThreadList != NULL) {
  1649. MmFreeNonPagedPool(ThreadList);
  1650. }
  1651. return Status;
  1652. }
  1653. VOID
  1654. SppProcessNewProcess (
  1655. PROCESS_ID ProcessId
  1656. )
  1657. /*++
  1658. Routine Description:
  1659. This routine collects statistics on a created process.
  1660. Arguments:
  1661. ProcessId - Supplies the ID of the process being created.
  1662. Return Value:
  1663. None.
  1664. --*/
  1665. {
  1666. BOOL Added;
  1667. PPROFILER_THREAD_NEW_PROCESS Event;
  1668. ULONG MaxNameSize;
  1669. PSTR Name;
  1670. ULONG NameSize;
  1671. RUNLEVEL OldRunLevel;
  1672. PPROCESS_INFORMATION Process;
  1673. ULONG ProcessorNumber;
  1674. ULONG ProcessSize;
  1675. KSTATUS Status;
  1676. if ((SpEnabledFlags & PROFILER_TYPE_FLAG_THREAD_STATISTICS) == 0) {
  1677. return;
  1678. }
  1679. ProcessSize = PROFILER_PROCESS_INFORMATION_SIZE;
  1680. Process = MmAllocateNonPagedPool(ProcessSize, SP_ALLOCATION_TAG);
  1681. if (Process == NULL) {
  1682. Status = STATUS_INSUFFICIENT_RESOURCES;
  1683. goto ProcessNewProcessEnd;
  1684. }
  1685. Process->Version = PROCESS_INFORMATION_VERSION;
  1686. Status = PsGetProcessInformation(ProcessId, Process, &ProcessSize);
  1687. if (!KSUCCESS(Status)) {
  1688. goto ProcessNewProcessEnd;
  1689. }
  1690. MaxNameSize = SCRATCH_BUFFER_LENGTH -
  1691. FIELD_OFFSET(PROFILER_THREAD_NEW_PROCESS, Name);
  1692. NameSize = Process->NameLength * sizeof(CHAR);
  1693. if (NameSize > MaxNameSize) {
  1694. NameSize = MaxNameSize;
  1695. }
  1696. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  1697. ProcessorNumber = KeGetCurrentProcessorNumber();
  1698. Event = (PVOID)(SpThreadStatisticsArray[ProcessorNumber]->Scratch);
  1699. Event->EventType = ProfilerThreadEventNewProcess;
  1700. Event->StructureSize = sizeof(PROFILER_THREAD_NEW_PROCESS);
  1701. if (NameSize != 0) {
  1702. Event->StructureSize -= ANYSIZE_ARRAY * sizeof(CHAR);
  1703. Event->StructureSize += NameSize;
  1704. Name = (PSTR)((PVOID)Process + Process->NameOffset);
  1705. RtlStringCopy(Event->Name, Name, NameSize);
  1706. } else {
  1707. Event->Name[0] = STRING_TERMINATOR;
  1708. }
  1709. Event->ProcessId = Process->ProcessId;
  1710. Event->TimeCounter = HlQueryTimeCounter();
  1711. Added = SppWriteProfilerBuffer(SpThreadStatisticsArray[ProcessorNumber],
  1712. (BYTE *)Event,
  1713. Event->StructureSize);
  1714. if (Added == FALSE) {
  1715. Status = STATUS_BUFFER_TOO_SMALL;
  1716. }
  1717. KeLowerRunLevel(OldRunLevel);
  1718. Status = STATUS_SUCCESS;
  1719. ProcessNewProcessEnd:
  1720. if (!KSUCCESS(Status)) {
  1721. RtlDebugPrint("Warning: Unable to add profiling event for new "
  1722. "process %d.\n",
  1723. ProcessId);
  1724. }
  1725. if (Process != NULL) {
  1726. MmFreeNonPagedPool(Process);
  1727. }
  1728. return;
  1729. }
  1730. VOID
  1731. SppProcessNewThread (
  1732. PROCESS_ID ProcessId,
  1733. THREAD_ID ThreadId
  1734. )
  1735. /*++
  1736. Routine Description:
  1737. This routine collects statistics on a created thread.
  1738. Arguments:
  1739. ProcessId - Supplies the ID of the process creating the new thread.
  1740. ThreadId - Supplies the ID of the new thread being created.
  1741. Return Value:
  1742. None.
  1743. --*/
  1744. {
  1745. BOOL Added;
  1746. PPROFILER_THREAD_NEW_THREAD Event;
  1747. ULONG NameSize;
  1748. RUNLEVEL OldRunLevel;
  1749. ULONG ProcessorNumber;
  1750. KSTATUS Status;
  1751. PTHREAD_INFORMATION Thread;
  1752. ULONG ThreadSize;
  1753. if ((SpEnabledFlags & PROFILER_TYPE_FLAG_THREAD_STATISTICS) == 0) {
  1754. return;
  1755. }
  1756. ThreadSize = PROFILER_THREAD_INFORMATION_SIZE;
  1757. Thread = MmAllocateNonPagedPool(ThreadSize, SP_ALLOCATION_TAG);
  1758. if (Thread == NULL) {
  1759. Status = STATUS_INSUFFICIENT_RESOURCES;
  1760. goto ProcessNewThreadEnd;
  1761. }
  1762. Status = PsGetThreadInformation(ProcessId, ThreadId, Thread, &ThreadSize);
  1763. if (!KSUCCESS(Status)) {
  1764. goto ProcessNewThreadEnd;
  1765. }
  1766. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  1767. ProcessorNumber = KeGetCurrentProcessorNumber();
  1768. Event = (PVOID)(SpThreadStatisticsArray[ProcessorNumber]->Scratch);
  1769. Event->EventType = ProfilerThreadEventNewThread;
  1770. ASSERT(Thread->StructureSize >= sizeof(THREAD_INFORMATION));
  1771. NameSize = Thread->StructureSize -
  1772. FIELD_OFFSET(THREAD_INFORMATION, Name);
  1773. ASSERT(NameSize < ThreadSize);
  1774. Event->StructureSize = sizeof(PROFILER_THREAD_NEW_THREAD) -
  1775. (ANYSIZE_ARRAY * sizeof(CHAR)) + NameSize;
  1776. Event->ProcessId = ProcessId;
  1777. Event->ThreadId = Thread->ThreadId;
  1778. Event->TimeCounter = HlQueryTimeCounter();
  1779. RtlStringCopy(Event->Name, Thread->Name, NameSize);
  1780. Added = SppWriteProfilerBuffer(SpThreadStatisticsArray[ProcessorNumber],
  1781. (BYTE *)Event,
  1782. Event->StructureSize);
  1783. if (Added == FALSE) {
  1784. Status = STATUS_BUFFER_TOO_SMALL;
  1785. }
  1786. KeLowerRunLevel(OldRunLevel);
  1787. Status = STATUS_SUCCESS;
  1788. ProcessNewThreadEnd:
  1789. if (!KSUCCESS(Status)) {
  1790. RtlDebugPrint("Warning: Unable to add profiling event for new "
  1791. "thread %d (Process %d).\n",
  1792. ThreadId,
  1793. ProcessId);
  1794. }
  1795. if (Thread != NULL) {
  1796. MmFreeNonPagedPool(Thread);
  1797. }
  1798. return;
  1799. }
  1800. VOID
  1801. SppDestroyThreadStatistics (
  1802. ULONG Phase
  1803. )
  1804. /*++
  1805. Routine Description:
  1806. This routine tears down thread profiling. Phase 0 stops the thread
  1807. statistics producers and consumers. Phase 1 cleans up resources.
  1808. Arguments:
  1809. Phase - Supplies the current phase of the destruction process.
  1810. Return Value:
  1811. None.
  1812. --*/
  1813. {
  1814. ULONG Index;
  1815. ASSERT(KeGetRunLevel() == RunLevelLow);
  1816. ASSERT(KeIsQueuedLockHeld(SpProfilingQueuedLock) != FALSE);
  1817. ASSERT(SpThreadStatisticsArray != NULL);
  1818. ASSERT(SpThreadStatisticsArraySize != 0);
  1819. if (Phase == 0) {
  1820. ASSERT((SpEnabledFlags & PROFILER_TYPE_FLAG_THREAD_STATISTICS) != 0);
  1821. //
  1822. // Disable thread statistics before disabling the profiler function to
  1823. // prevent any pending producers from touching the buffers after they
  1824. // are released
  1825. //
  1826. SpEnabledFlags &= ~PROFILER_TYPE_FLAG_THREAD_STATISTICS;
  1827. //
  1828. // Clear the function pointer to officially take the profiling down.
  1829. //
  1830. SpCollectThreadStatisticRoutine = NULL;
  1831. RtlMemoryBarrier();
  1832. } else {
  1833. ASSERT(Phase == 1);
  1834. ASSERT((SpEnabledFlags & PROFILER_TYPE_FLAG_THREAD_STATISTICS) == 0);
  1835. //
  1836. // Destroy the stack sampling array.
  1837. //
  1838. for (Index = 0; Index < SpThreadStatisticsArraySize; Index += 1) {
  1839. if (SpThreadStatisticsArray[Index] != NULL) {
  1840. MmFreeNonPagedPool(SpThreadStatisticsArray[Index]);
  1841. }
  1842. }
  1843. MmFreeNonPagedPool(SpThreadStatisticsArray);
  1844. SpThreadStatisticsArray = NULL;
  1845. SpThreadStatisticsArraySize = 0;
  1846. }
  1847. return;
  1848. }
  1849. VOID
  1850. SppCollectThreadStatistic (
  1851. PKTHREAD Thread,
  1852. PPROCESSOR_BLOCK Processor,
  1853. SCHEDULER_REASON ScheduleOutReason
  1854. )
  1855. /*++
  1856. Routine Description:
  1857. This routine collects statistics on a thread that is being scheduled out.
  1858. This routine must be called at dispatch level inside the scheduler.
  1859. Arguments:
  1860. Thread - Supplies a pointer to the thread being scheduled out.
  1861. Processor - Supplies a pointer to the executing processor block.
  1862. ScheduleOutReason - Supplies the reason the thread is being scheduled out.
  1863. Return Value:
  1864. None.
  1865. --*/
  1866. {
  1867. PPROFILER_CONTEXT_SWAP ContextSwap;
  1868. ULONG ProcessorNumber;
  1869. if ((SpEnabledFlags & PROFILER_TYPE_FLAG_THREAD_STATISTICS) == 0) {
  1870. return;
  1871. }
  1872. //
  1873. // Do not collect data on processors that have not been initialized for
  1874. // profiling.
  1875. //
  1876. if (Processor->ProcessorNumber >= SpThreadStatisticsArraySize) {
  1877. return;
  1878. }
  1879. ProcessorNumber = Processor->ProcessorNumber;
  1880. ASSERT(sizeof(PROFILER_CONTEXT_SWAP) < SCRATCH_BUFFER_LENGTH);
  1881. ContextSwap = (PVOID)(SpThreadStatisticsArray[ProcessorNumber]->Scratch);
  1882. ContextSwap->EventType = ScheduleOutReason;
  1883. ContextSwap->TimeCount = HlQueryTimeCounter();
  1884. ContextSwap->BlockingQueue = (UINTN)NULL;
  1885. if (ScheduleOutReason == SchedulerReasonThreadBlocking) {
  1886. ContextSwap->BlockingQueue = (UINTN)(ObGetBlockingQueue(Thread));
  1887. }
  1888. ContextSwap->ThreadId = Thread->ThreadId;
  1889. ContextSwap->ProcessId = Thread->OwningProcess->Identifiers.ProcessId;
  1890. //
  1891. // Write the data to the sampling buffer.
  1892. //
  1893. SppWriteProfilerBuffer(SpThreadStatisticsArray[ProcessorNumber],
  1894. (BYTE *)ContextSwap,
  1895. sizeof(PROFILER_CONTEXT_SWAP));
  1896. return;
  1897. }