Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

987 lines
23 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. icecap.c
  5. Abstract:
  6. This module implements the probe and support routines for
  7. kernel icecap tracing.
  8. Author:
  9. Rick Vicik (rickv) 10-Aug-2001
  10. Revision History:
  11. --*/
  12. #ifdef _CAPKERN
  13. #include <ntos.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <zwapi.h>
  17. #include <stdio.h>
  18. #define InterlockedExchangeAddPtr _InterlockedExchangeAdd64
  19. #define GetTS() __getReg(CV_IA64_ApITC) // Timestamp
  20. #define GetPMD4() __getReg(CV_IA64_PFD4) // PMD[4]
  21. #define GetPMD5() __getReg(CV_IA64_PFD5) // PMD[5]
  22. #define PutPMC4() __getReg(CV_IA64_PFC4) // PMC[4]
  23. //
  24. // Kernel Icecap logs to Perfmem (BBTBuffer) using the following format:
  25. //
  26. // BBTBuffer[0] contains the length in pages (4k or 8k)
  27. // BBTBuffer[1] is a flagword: 1 = trace
  28. // 2 = RDPMD4
  29. // 4 = user stack dump
  30. // BBTBuffer[2] is ptr to beginning of cpu0 buffer
  31. // BBTBuffer[3] is ptr to beginning of cpu1 buffer (also end of cpu0 buffer)
  32. // BBTBuffer[4] is ptr to beginning of cpu2 buffer (also end of cpu1 buffer)
  33. // ...
  34. // BBTBuffer[n+2] is ptr to beginning of cpu 'n' buffer (also end of cpu 'n-1' buffer)
  35. // BBTBuffer[n+3] is ptr the end of cpu 'n' buffer
  36. //
  37. // The area starting with &BBTBuffer[n+4] is divided into private buffers
  38. // for each cpu. The first dword in each cpu-private buffer points to the
  39. // beginning of freespace in that buffer. Each one is initialized to point
  40. // just after itself. Space is claimed using lock xadd on that dword.
  41. // If the resulting value points beyond the beginning of the next cpu's
  42. // buffer, this buffer is considered full and nothing further is logged.
  43. // Each cpu's freespace pointer is in a separate cacheline.
  44. //
  45. // Sizes of trace records
  46. //
  47. typedef struct CapEnter
  48. {
  49. char type;
  50. char spare;
  51. short size;
  52. void* current;
  53. void* child;
  54. SIZE_T stack;
  55. ULONGLONG timestamp;
  56. ULONGLONG ctr2[1];
  57. } CAPENTER;
  58. typedef struct CapExit
  59. {
  60. char type;
  61. char spare;
  62. short size;
  63. void* current;
  64. ULONGLONG timestamp;
  65. ULONGLONG ctr2[1];
  66. } CAPEXIT;
  67. typedef struct CapTID
  68. {
  69. char type;
  70. char spare;
  71. short size;
  72. ULONG Pid;
  73. ULONG Tid;
  74. char ImageName[20];
  75. } CAPTID;
  76. typedef struct CapNINT
  77. {
  78. char type;
  79. char spare;
  80. short size;
  81. ULONG_PTR Data[1];
  82. } CAPNINT;
  83. //
  84. // The pre-call (CAP_Start_Profiling) and post-call (CAP_End_Profiling)
  85. // probe calls are defined in RTL because they must be built twice:
  86. // once for kernel runtime and once for user-mode runtime (because the
  87. // technique for getting the trace buffer address is different).
  88. //
  89. #ifdef NTOS_KERNEL_RUNTIME
  90. ULONG RtlWalkFrameChain (
  91. OUT PVOID *Callers,
  92. IN ULONG Count,
  93. IN ULONG Flags
  94. );
  95. //
  96. // Kernel-Mode Probe & Support Routines:
  97. // (BBTBuffer address obtained from kglobal pointer *BBTBuffer,
  98. // cpu number obtained from PCR)
  99. //
  100. extern SIZE_T *BBTBuffer;
  101. VOID
  102. __stdcall
  103. _CAP_Start_Profiling(
  104. PVOID Current,
  105. PVOID Child)
  106. /*++
  107. Routine description:
  108. Kernel-mode version of before-call icecap probe. Logs a type 5
  109. icecap record into the part of BBTBuffer for the current cpu
  110. (obtained from Prcb). Inserts adrs of current and called functions
  111. plus ITC timestamp into logrecord. If BBTBuffer flag 2 set,
  112. also copies PMD 4 into logrecord.
  113. Uses InterlockedAdd to claim buffer space without the need for spinlocks.
  114. Arguments:
  115. current - address of routine which did the call
  116. child - address of called routine
  117. --*/
  118. {
  119. SIZE_T* CpuPtr;
  120. CAPENTER* RecPtr;
  121. int size = sizeof(CAPENTER) -8;
  122. if( !BBTBuffer || !(BBTBuffer[1]&1) )
  123. return;
  124. CpuPtr = BBTBuffer + KeGetCurrentProcessorNumber() + 2;
  125. if( !( *CpuPtr ) || *((SIZE_T*)(*CpuPtr)) > *(CpuPtr+1) )
  126. return;
  127. if ( BBTBuffer[1] & 2 )
  128. size += 8;
  129. else if ( BBTBuffer[1] & 8 )
  130. size += 16;
  131. RecPtr = (CAPENTER*)InterlockedExchangeAddPtr( (SIZE_T*)(*CpuPtr), size);
  132. if( (((SIZE_T)RecPtr)+size) >= *(CpuPtr+1) )
  133. return;
  134. RecPtr->type = 5;
  135. RecPtr->spare = 0;
  136. RecPtr->size = size-4;
  137. RecPtr->current = Current;
  138. RecPtr->child = Child;
  139. RecPtr->stack = (SIZE_T)PsGetCurrentThread()->Cid.UniqueThread;
  140. RecPtr->timestamp = GetTS();
  141. if( size >= sizeof(CAPENTER) )
  142. RecPtr->ctr2[0] = GetPMD4();
  143. if( size == sizeof(CAPENTER)+8 )
  144. RecPtr->ctr2[1] = GetPMD5();
  145. return;
  146. }
  147. VOID
  148. __stdcall
  149. _CAP_End_Profiling(
  150. PVOID Current)
  151. /*++
  152. Routine description:
  153. Kernel-mode version of after-call icecap probe. Logs a type 6
  154. icecap record into the part of BBTBuffer for the current cpu
  155. (obtained from Prcb). Inserts adr of current function and
  156. ITC timestamp into logrecord. If BBTBuffer flag 2 set,
  157. also copies PMD 4 into logrecord.
  158. Uses InterlockedAdd to claim buffer space without the need for spinlocks.
  159. Arguments:
  160. current - address of routine which did the call
  161. --*/
  162. {
  163. SIZE_T* CpuPtr;
  164. CAPEXIT* RecPtr;
  165. int size = sizeof(CAPEXIT) -8;
  166. if( !BBTBuffer || !(BBTBuffer[1]&1) )
  167. return;
  168. CpuPtr = BBTBuffer + KeGetCurrentProcessorNumber() + 2;
  169. if( !( *CpuPtr ) || *((SIZE_T*)(*CpuPtr)) > *(CpuPtr+1) )
  170. return;
  171. if( BBTBuffer[1] & 2 )
  172. size += 8;
  173. else if( BBTBuffer[1] & 8 )
  174. size += 16;
  175. RecPtr = (CAPEXIT*)InterlockedExchangeAddPtr( (SIZE_T*)(*CpuPtr), size);
  176. if( (((SIZE_T)RecPtr)+size) >= *(CpuPtr+1) )
  177. return;
  178. RecPtr->type = 6;
  179. RecPtr->spare = 0;
  180. RecPtr->size = size-4;
  181. RecPtr->current = Current;
  182. RecPtr->timestamp = GetTS();
  183. if( size >= sizeof(CAPEXIT) )
  184. RecPtr->ctr2[0] = GetPMD4();
  185. if( size == sizeof(CAPEXIT)+8 )
  186. RecPtr->ctr2[1] = GetPMD5();
  187. return;
  188. }
  189. VOID
  190. __stdcall
  191. _CAP_ThreadID( VOID )
  192. /*++
  193. Routine description:
  194. Called by KiSystemService before executing the service routine.
  195. Logs a type 14 icecap record containing Pid, Tid & image file name.
  196. Optionally, if BBTBuffer flag 2 set, runs the stack frame pointers
  197. in the user-mode call stack starting with the trap frame and copies
  198. the return addresses to the log record. The length of the logrecord
  199. indicates whether user call stack info is included.
  200. --*/
  201. {
  202. if( !BBTBuffer || !(BBTBuffer[1]&1) )
  203. return;
  204. {
  205. PEPROCESS Process;
  206. PKTHREAD Thread;
  207. PETHREAD EThread;
  208. CAPTID* RecPtr;
  209. SIZE_T* CpuPtr;
  210. int callcnt;
  211. ULONG recsize;
  212. SIZE_T RetAddr[7];
  213. if( !BBTBuffer || !(BBTBuffer[1]&1) )
  214. return;
  215. CpuPtr = BBTBuffer + KeGetCurrentProcessorNumber() + 2;
  216. if( !( *CpuPtr ) || *((SIZE_T*)(*CpuPtr)) > *(CpuPtr+1) )
  217. return;
  218. callcnt = 0;
  219. recsize = sizeof(CAPTID);
  220. Thread = KeGetCurrentThread();
  221. EThread = CONTAINING_RECORD(Thread,ETHREAD,Tcb);
  222. // if trapframe, count call-frames to determine record size
  223. if( (BBTBuffer[1] & 4) && EThread->Tcb.PreviousMode != KernelMode ) {
  224. PTEB Teb;
  225. SIZE_T *FramePtr;
  226. callcnt = RtlWalkFrameChain((PVOID*)RetAddr,7,0);
  227. FramePtr = (SIZE_T*)EThread->Tcb.TrapFrame; // get trap frame
  228. Teb = EThread->Tcb.Teb;
  229. DbgPrint("TrapFrame=%#x, 3rd RetAdr=%p\n",
  230. Thread->TrapFrame, RetAddr[2] );
  231. recsize += (callcnt<<3);
  232. }
  233. RecPtr = (CAPTID*)InterlockedExchangeAddPtr( (SIZE_T*)(*CpuPtr), recsize);
  234. if( (((SIZE_T)RecPtr)+recsize) >= *(CpuPtr+1) )
  235. return;
  236. // initialize CapThreadID record (type 14)
  237. RecPtr->type = 14;
  238. RecPtr->spare = 0;
  239. // insert data length (excluding 4byte header)
  240. RecPtr->size = (SHORT)recsize-4;
  241. // insert Pid & Tid
  242. RecPtr->Pid = HandleToUlong(EThread->Cid.UniqueProcess);
  243. RecPtr->Tid = HandleToUlong(EThread->Cid.UniqueThread);
  244. // insert ImageFile name
  245. Process = CONTAINING_RECORD(Thread->ApcState.Process,EPROCESS,Pcb);
  246. memcpy(&RecPtr->ImageName, Process->ImageFileName, 16 );
  247. // insert optional user call stack data
  248. if( recsize > sizeof(CAPTID) && (callcnt-2) )
  249. memcpy( ((char*)RecPtr)+sizeof(CAPTID), RetAddr+2, ((callcnt-2)<<3) );
  250. }
  251. }
  252. VOID
  253. __stdcall
  254. _CAP_SetCPU( VOID )
  255. /*++
  256. Routine description:
  257. Called by KiSystemService before returning to user mode.
  258. Sets current cpu number in Teb->Spare3 (+0xf78) so user-mode version
  259. of probe functions know which part of BBTBuffer to use.
  260. --*/
  261. {
  262. SIZE_T *CpuPtr;
  263. ULONG cpu;
  264. PTEB Teb;
  265. if( !BBTBuffer || !(BBTBuffer[1]&1) )
  266. return;
  267. cpu = KeGetCurrentProcessorNumber();
  268. CpuPtr = BBTBuffer + cpu + 2;
  269. if( !( *CpuPtr ) || *((SIZE_T*)(*CpuPtr)) > *(CpuPtr+1) ||
  270. !(Teb = NtCurrentTeb()) )
  271. return;
  272. try {
  273. Teb->Spare3 = cpu;
  274. } except(EXCEPTION_EXECUTE_HANDLER) {
  275. NOTHING;
  276. }
  277. }
  278. #else
  279. //
  280. // User-Mode Probe Routines (for ntdll, win32k, etc.)
  281. // (BBTBuffer address & cpu obtained from Teb)
  282. //
  283. VOID
  284. __stdcall
  285. _CAP_Start_Profiling(
  286. PVOID Current,
  287. PVOID Child)
  288. /*++
  289. Routine description:
  290. user-mode version of before-call icecap probe. Logs a type 5
  291. icecap record into the part of BBTBuffer for the current cpu
  292. (obtained from Teb+0xf78). Inserts adrs of current and called
  293. functions plus ITC timestamp into logrecord. If BBTBuffer
  294. flag 2 set, also copies PMD 4 into logrecord.
  295. Uses InterlockedAdd to claim buffer space without the need for spinlocks.
  296. Arguments:
  297. current - address of routine which did the call
  298. child - address of called routine
  299. --*/
  300. {
  301. TEB* Teb = NtCurrentTeb();
  302. SIZE_T* BBTBuffer = Teb->ReservedForPerf;
  303. SIZE_T* CpuPtr;
  304. CAPENTER* RecPtr;
  305. int size = sizeof(CAPENTER) -8;
  306. if( !BBTBuffer || !(BBTBuffer[1]&1) )
  307. return;
  308. CpuPtr = BBTBuffer + Teb->Spare3 + 2;
  309. if( !( *CpuPtr ) || *((SIZE_T*)(*CpuPtr)) > *(CpuPtr+1) )
  310. return;
  311. if( BBTBuffer[1] & 2 )
  312. size += 8;
  313. if( BBTBuffer[1] & 8 )
  314. size += 8;
  315. RecPtr = (CAPENTER*)InterlockedExchangeAddPtr( (SIZE_T*)(*CpuPtr), size);
  316. if( (((SIZE_T)RecPtr)+size) >= *(CpuPtr+1) )
  317. return;
  318. RecPtr->type = 5;
  319. RecPtr->spare = 0;
  320. RecPtr->size = size-4;
  321. RecPtr->current = Current;
  322. RecPtr->child = Child;
  323. RecPtr->stack = (SIZE_T)Teb->ClientId.UniqueThread;
  324. RecPtr->timestamp = GetTS();
  325. if( size >= sizeof(CAPENTER) )
  326. RecPtr->ctr2[0] = GetPMD4();
  327. if( size == sizeof(CAPENTER)+8 )
  328. RecPtr->ctr2[1] = GetPMD5();
  329. }
  330. VOID
  331. __stdcall
  332. _CAP_End_Profiling(
  333. PVOID Current)
  334. /*++
  335. Routine description:
  336. user-mode version of after-call icecap probe. Logs a type 6
  337. icecap record into the part of BBTBuffer for the current cpu
  338. (obtained from Teb+0xf78). Inserts adr of current function
  339. plus RDTSC timestamp into logrecord. If BBTBuffer flag 2 set,
  340. also copies PMD 4 into logrecord.
  341. Uses InterlockedAdd to claim buffer space without the need for spinlocks.
  342. Arguments:
  343. current - address of routine which did the call
  344. --*/
  345. {
  346. TEB* Teb = NtCurrentTeb();
  347. SIZE_T* BBTBuffer = Teb->ReservedForPerf;
  348. SIZE_T* CpuPtr;
  349. CAPEXIT* RecPtr;
  350. int size = sizeof(CAPEXIT) -8;
  351. if( !BBTBuffer || !(BBTBuffer[1]&1) )
  352. return;
  353. CpuPtr = BBTBuffer + Teb->Spare3 + 2;
  354. if( !( *CpuPtr ) || *((SIZE_T*)(*CpuPtr)) > *(CpuPtr+1) )
  355. return;
  356. if( BBTBuffer[1] & 2 )
  357. size += 8;
  358. if( BBTBuffer[1] & 8 )
  359. size += 8;
  360. RecPtr = (CAPEXIT*)InterlockedExchangeAddPtr( (SIZE_T*)(*CpuPtr), size);
  361. if( (((SIZE_T)RecPtr)+size) >= *(CpuPtr+1) )
  362. return;
  363. RecPtr->type = 6;
  364. RecPtr->spare = 0;
  365. RecPtr->size = size-4;
  366. RecPtr->current = Current;
  367. RecPtr->timestamp = GetTS();
  368. if( size >= sizeof(CAPEXIT) )
  369. RecPtr->ctr2[0] = GetPMD4();
  370. if( size == sizeof(CAPEXIT)+8 )
  371. RecPtr->ctr2[1] = GetPMD5();
  372. }
  373. #endif
  374. //
  375. // Common Support Routines
  376. // (method for getting BBTBuffer address & cpu ifdef'ed for kernel & user)
  377. //
  378. VOID
  379. __stdcall
  380. _CAP_Log_1Int(
  381. ULONG code,
  382. SIZE_T data)
  383. /*++
  384. Routine description:
  385. User-mode version of general-purpose log integer probe.
  386. Logs a type 15 icecap record into the part of BBTBuffer for the
  387. current cpu (obtained from Prcb). Inserts code into the byte after
  388. length, ITC timestamp and the value of 'data'.
  389. Uses lock xadd to claim buffer space without the need for spinlocks.
  390. Arguments:
  391. code - type-code for trace formatting
  392. data - ULONG value to be logged
  393. --*/
  394. {
  395. SIZE_T* CpuPtr;
  396. CAPEXIT* RecPtr;
  397. int cpu,size;
  398. #ifndef NTOS_KERNEL_RUNTIME
  399. TEB* Teb = NtCurrentTeb();
  400. SIZE_T* BBTBuffer = Teb->ReservedForPerf;
  401. cpu = Teb->Spare3;
  402. #else
  403. cpu = KeGetCurrentProcessorNumber();
  404. #endif
  405. if( !BBTBuffer || !(BBTBuffer[1]&1) )
  406. return;
  407. CpuPtr = BBTBuffer + cpu + 2;
  408. CpuPtr = BBTBuffer + KeGetCurrentProcessorNumber() + 2;
  409. if( !( *CpuPtr ) || *((SIZE_T*)(*CpuPtr)) > *(CpuPtr+1) )
  410. return;
  411. size = sizeof(CAPENTER) -8;
  412. RecPtr = (CAPEXIT*)InterlockedExchangeAddPtr( (SIZE_T*)(*CpuPtr), size);
  413. if( (((SIZE_T)RecPtr)+size) >= *(CpuPtr+1) )
  414. return;
  415. RecPtr->type = 15;
  416. RecPtr->spare = (char)code;
  417. RecPtr->size = size-4;
  418. RecPtr->current = (PVOID)data;
  419. RecPtr->timestamp = GetTS();
  420. return;
  421. }
  422. VOID
  423. CAPKComment(
  424. char* Format, ...)
  425. /*++
  426. Routine description:
  427. Logs a free-form comment (record type 13) in the icecap trace
  428. Arguments:
  429. Format - printf-style format string and substitutional parms
  430. --*/
  431. {
  432. SIZE_T* CpuPtr;
  433. UCHAR Buffer[512];
  434. int cb, insize, outsize;
  435. CAPEXIT* RecPtr;
  436. char* data;
  437. va_list arglist;
  438. #ifndef NTOS_KERNEL_RUNTIME
  439. TEB* Teb = NtCurrentTeb();
  440. SIZE_T* BBTBuffer = Teb->ReservedForPerf;
  441. cb = Teb->Spare3;
  442. #else
  443. cb = KeGetCurrentProcessorNumber();
  444. #endif
  445. if( !BBTBuffer || !(BBTBuffer[1]&1) )
  446. return;
  447. CpuPtr = BBTBuffer + cb + 2;
  448. if( !( *CpuPtr ) || *((SIZE_T*)(*CpuPtr)) > *(CpuPtr+1) )
  449. return;
  450. va_start(arglist, Format);
  451. cb = _vsnprintf(Buffer, sizeof(Buffer), Format, arglist);
  452. va_end(arglist);
  453. if (cb == -1) { // detect buffer overflow
  454. cb = sizeof(Buffer);
  455. Buffer[sizeof(Buffer) - 1] = '\n';
  456. }
  457. data = &Buffer[0];
  458. insize = strlen(data); // save insize for data copy
  459. outsize = ((insize+11) & 0xfffffff8); // pad outsize to SIZE_T boundary
  460. // (+4 for hdr, +3 to pad)
  461. RecPtr = (CAPEXIT*)InterlockedExchangeAddPtr( (SIZE_T*)(*CpuPtr), outsize);
  462. if( (((SIZE_T)RecPtr)+outsize) >= *(CpuPtr+1) )
  463. return;
  464. // size in tracerec excludes 4byte hdr
  465. outsize -= 4;
  466. // initialize CapkComment record (type 13)
  467. RecPtr->type = 13;
  468. RecPtr->spare = 0;
  469. // insert size
  470. RecPtr->size = (short)outsize;
  471. // insert sprintf data right after 4byte hdr
  472. memcpy(((char*)RecPtr)+4, data, insize );
  473. // if had to pad, add null terminator to string
  474. if( outsize > insize )
  475. *( (((char*)RecPtr) + 4) + insize) = 0;
  476. }
  477. VOID
  478. __cdecl
  479. CAP_Log_NInt_Clothed(
  480. ULONG Bcode_Bts_Scount,
  481. /*
  482. UCHAR code,
  483. UCHAR log_timestamp,
  484. USHORT intcount,
  485. */
  486. ...)
  487. /*++
  488. Routine description:
  489. Kernel-mode and User-mode versions of general-purpose log integer probe.
  490. Logs a type 16 icecap record into the part of BBTBuffer for the
  491. current cpu (obtained from Prcb). Inserts lowest byte of code into the
  492. byte after length, the RDTSC timestamp (if log_timestamp != 0), and
  493. intcount ULONG_PTRs. Uses lock xadd to claim buffer space without the need
  494. for spinlocks.
  495. Arguments:
  496. code - type-code for trace formatting (really only a single byte)
  497. log_timestamp - non-zero if timestamp should be logged
  498. intcount - number of ULONG_PTRs to log
  499. remaining arguments - ULONG_PTR value(s) to be logged
  500. --*/
  501. {
  502. SIZE_T* CpuPtr;
  503. CAPNINT* RecPtr;
  504. int cpu,size;
  505. BOOLEAN logts;
  506. ULONG count;
  507. ULONG i = 0;
  508. va_list marker;
  509. #ifndef NTOS_KERNEL_RUNTIME
  510. TEB* Teb = NtCurrentTeb();
  511. SIZE_T* BBTBuffer = Teb->ReservedForPerf;
  512. cpu = Teb->Spare3;
  513. #else
  514. cpu = KeGetCurrentProcessorNumber();
  515. #endif
  516. logts = (Bcode_Bts_Scount & 0xFF00) != 0;
  517. count = (Bcode_Bts_Scount & 0xFFFF0000) >> 16;
  518. if( !BBTBuffer || !(BBTBuffer[1]&1) )
  519. return;
  520. CpuPtr = BBTBuffer + cpu + 2;
  521. //CpuPtr = BBTBuffer + KeGetCurrentProcessorNumber() + 2;
  522. if( !( *CpuPtr ) || *((SIZE_T*)(*CpuPtr)) > *(CpuPtr+1) )
  523. return;
  524. size = sizeof(CAPNINT) + count * sizeof (ULONG_PTR);
  525. if (logts)
  526. size += 8;
  527. RecPtr = (CAPNINT*)InterlockedExchangeAddPtr( (SIZE_T*)(*CpuPtr), size);
  528. if( (((SIZE_T)RecPtr)+size) >= *(CpuPtr+1) )
  529. return;
  530. RecPtr->type = 16;
  531. RecPtr->spare = (char) (Bcode_Bts_Scount & 0xFF);
  532. RecPtr->size = size - 4;
  533. if (logts) {
  534. RecPtr->Data[0] = GetTS();
  535. i++;
  536. }
  537. va_start (marker, Bcode_Bts_Scount);
  538. while (count-- > 0)
  539. RecPtr->Data[i++] = va_arg (marker, ULONG_PTR);
  540. va_end (marker);
  541. RecPtr->Data[i] = (ULONG_PTR)_ReturnAddress();
  542. return;
  543. }
  544. //
  545. // Constants for CAPKControl
  546. //
  547. #define CAPKStart 1
  548. #define CAPKStop 2
  549. #define CAPKResume 3
  550. #define MAXDUMMY 30
  551. #define CAPK0 4
  552. #define PAGESIZE 8192
  553. ULONG CpuNumber;
  554. VOID
  555. __stdcall
  556. CAPK_Calibrate_Start_Profiling(
  557. PVOID Current,
  558. PVOID Child)
  559. /*++
  560. Routine description:
  561. Calibration version of before-call icecap probe. Logs a type 5
  562. icecap record into the part of BBTBuffer for the current cpu
  563. (obtained from Teb+0xf78). Inserts adrs of current and called
  564. functions plus RDTSC timestamp into logrecord. If BBTBuffer
  565. flag 1 set, also does RDPMC 0 and inserts result into logrecord.
  566. Uses InterlockedAdd to claim buffer space without the need for spinlocks.
  567. Slightly modified for use here (invert checking of 'GO' bit and
  568. use global CpuNumber)
  569. Arguments:
  570. current - address of routine which did the call
  571. child - address of called routine
  572. --*/
  573. {
  574. SIZE_T* CpuPtr;
  575. CAPENTER* RecPtr;
  576. int size = sizeof(CAPENTER) -8;
  577. #ifndef NTOS_KERNEL_RUNTIME
  578. SIZE_T* BBTBuffer = NtCurrentTeb()->ReservedForPerf;
  579. #endif
  580. if( !BBTBuffer || (BBTBuffer[1]&1) ) // note 1 bit is opposite
  581. return;
  582. CpuPtr = BBTBuffer + CpuNumber + 2;
  583. if( !( *CpuPtr ) || *((SIZE_T*)(*CpuPtr)) > *(CpuPtr+1) )
  584. return;
  585. if ( BBTBuffer[1] & 2 )
  586. size += 8;
  587. else if ( BBTBuffer[1] & 8 )
  588. size += 16;
  589. RecPtr = (CAPENTER*)InterlockedExchangeAddPtr( (SIZE_T*)(*CpuPtr), size);
  590. if( (((SIZE_T)RecPtr)+size) >= *(CpuPtr+1) )
  591. return;
  592. RecPtr->type = 5;
  593. RecPtr->spare = 0;
  594. RecPtr->size = size-4;
  595. RecPtr->current = Current;
  596. RecPtr->child = Child;
  597. RecPtr->stack = (SIZE_T)PsGetCurrentThread()->Cid.UniqueThread;
  598. RecPtr->timestamp = GetTS();
  599. if( size >= sizeof(CAPENTER) )
  600. RecPtr->ctr2[0] = GetPMD4();
  601. if( size == sizeof(CAPENTER)+8 )
  602. RecPtr->ctr2[1] = GetPMD5();
  603. }
  604. VOID
  605. __stdcall
  606. CAPK_Calibrate_End_Profiling(
  607. PVOID Current)
  608. /*++
  609. Routine description:
  610. Calibration version of after-call icecap probe. Logs a type 6
  611. icecap record into the part of BBTBuffer for the current cpu
  612. (obtained from Teb+0xf78). Inserts adr of current function
  613. plus RDTSC timestamp into logrecord. If BBTBuffer flag 1 set,
  614. also does RDPMC 0 and inserts result into logrecord.
  615. Uses InterlockedAdd to claim buffer space without the need for spinlocks.
  616. Slightly modified for use here (invert checking of 'GO' bit and
  617. use global CpuNumber)
  618. Arguments:
  619. current - address of routine which did the call
  620. --*/
  621. {
  622. SIZE_T* CpuPtr;
  623. CAPEXIT* RecPtr;
  624. int size = sizeof(CAPENTER) -8;
  625. #ifndef NTOS_KERNEL_RUNTIME
  626. SIZE_T* BBTBuffer = NtCurrentTeb()->ReservedForPerf;
  627. #endif
  628. if( !BBTBuffer || (BBTBuffer[1]&1) ) // note 1 bit is opposite
  629. return;
  630. CpuPtr = BBTBuffer + CpuNumber + 2;
  631. if( !( *CpuPtr ) || *((SIZE_T*)(*CpuPtr)) > *(CpuPtr+1) )
  632. return;
  633. if( BBTBuffer[1] & 2 )
  634. size += 8;
  635. else if( BBTBuffer[1] & 8 )
  636. size += 16;
  637. RecPtr = (CAPEXIT*)InterlockedExchangeAddPtr( (SIZE_T*)(*CpuPtr), size);
  638. if( (((SIZE_T)RecPtr)+size) >= *(CpuPtr+1) )
  639. return;
  640. RecPtr->type = 6;
  641. RecPtr->spare = 0;
  642. RecPtr->size = size-4;
  643. RecPtr->current = Current;
  644. RecPtr->timestamp = GetTS();
  645. if( size >= sizeof(CAPEXIT) )
  646. RecPtr->ctr2[0] = GetPMD4();
  647. if( size == sizeof(CAPEXIT)+8 )
  648. RecPtr->ctr2[1] = GetPMD5();
  649. return;
  650. }
  651. int CAPKControl(
  652. ULONG opcode)
  653. /*++
  654. Routine description:
  655. CAPKControl
  656. Description:
  657. Starts, stops or pauses icecap tracing
  658. Arguments:
  659. opcode - 1=start, 2=stop, 3=resume, 4,5,6,7 reserved
  660. Return value:
  661. 1 = success, 0 = BBTBuf not set up
  662. --*/
  663. {
  664. ULONG cpus,pwords,percpusize;
  665. SIZE_T* ptr;
  666. #ifndef NTOS_KERNEL_RUNTIME
  667. SIZE_T* BBTBuffer = NtCurrentTeb()->ReservedForPerf;
  668. cpus = NtCurrentPeb()->NumberOfProcessors;
  669. #else
  670. cpus = KeNumberProcessors;
  671. #endif
  672. if( !BBTBuffer || !(BBTBuffer[0]) )
  673. return 0;
  674. pwords = CAPK0 + cpus;
  675. percpusize = ( ( *((PULONG)BBTBuffer) * (PAGESIZE/sizeof(SIZE_T)) ) - pwords)/cpus; // in words
  676. if(opcode == CAPKStart) { // start
  677. ULONG i,j;
  678. BBTBuffer[1] &= ~1; // stop
  679. // initialize the CpuPtrs
  680. for( i=0, ptr = BBTBuffer+pwords; i<cpus+1; i++, ptr+=percpusize)
  681. BBTBuffer[2+i] = (SIZE_T)ptr;
  682. // initialize each freeptr to next dword
  683. // (and log dummy records to calibrate overhead)
  684. for( i=0, ptr = BBTBuffer+pwords; i<cpus; i++, ptr+=percpusize)
  685. {
  686. *ptr = (SIZE_T) (ptr+1);
  687. CpuNumber = i;
  688. for( j=0; j<MAXDUMMY; j++ )
  689. {
  690. CAPK_Calibrate_Start_Profiling(NULL, NULL);
  691. CAPK_Calibrate_End_Profiling(NULL);
  692. }
  693. }
  694. BBTBuffer[1] |= 1; //start
  695. } else if( opcode == CAPKStop ) { // stop
  696. BBTBuffer[1] &= ~1;
  697. } else if( opcode == CAPKResume ) { //resume
  698. BBTBuffer[1] |= 1; //start
  699. } else {
  700. return 0; // invalid opcode
  701. }
  702. return 1;
  703. }
  704. #endif