Source code of Windows XP (NT5)
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.

591 lines
11 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. ntnap.c
  5. Abstract:
  6. This module contains the routines for initializing and performing
  7. profiling of NT API's.
  8. Author:
  9. Russ Blake (russbl) 22-Apr-1991
  10. Revision History:
  11. --*/
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <string.h>
  16. #include "ntnapdef.h"
  17. #include "ntnap.h"
  18. //
  19. // Initialization control: only want to initialize once; this
  20. // prevents multiple initializations before data segment and
  21. // global control are initialized.
  22. //
  23. BOOLEAN NapInitialized = FALSE;
  24. //
  25. // Counter frequency constant
  26. //
  27. LARGE_INTEGER NapFrequency;
  28. //
  29. // Profiling data structures
  30. //
  31. PNAPCONTROL NapControl = NULL;
  32. //
  33. // The following array is indexed by Service Number + 1. Service
  34. // Number -1 (element 0 of the following array) is reserved for
  35. // calibration. Initialization of this to NULL kicks off the
  36. // NapDllInit sequence to create or open the data section.
  37. //
  38. PNAPDATA NapProfilingData = NULL;
  39. VOID
  40. NapDllInit (
  41. VOID
  42. )
  43. /*++
  44. Routine Description:
  45. NapDllInit() is called before calling any profiling api. It
  46. initializes profiling for the NT native API's.
  47. NOTE: Initialization occurs only once and is controlled by
  48. the NapInitDone global flag.
  49. Arguments:
  50. None
  51. Return Value:
  52. None
  53. --*/
  54. {
  55. ULONG i;
  56. LARGE_INTEGER CurrentCounter;
  57. if (!NapInitialized) {
  58. //
  59. // Instance data for this process's ntdll.dll not yet initialized.
  60. //
  61. NapInitialized = TRUE;
  62. //
  63. // Get Counter frequency (current counter value is thrown away)
  64. // This call is not profiled because NapControl == NULL here.
  65. //
  66. NtQueryPerformanceCounter(&CurrentCounter,
  67. &NapFrequency);
  68. //
  69. // Allocate or open data section for api profiling data.
  70. //
  71. if (NT_SUCCESS(NapCreateDataSection(&NapControl))) {
  72. NapProfilingData = (PNAPDATA)(NapControl + 1);
  73. if (!NapControl->Initialized) {
  74. //
  75. // We are the first process to get here: we jsut
  76. // allocated the section, so must initialize it.
  77. //
  78. NapControl->Initialized = TRUE;
  79. NapControl->Paused = 0;
  80. //
  81. // Clear the data area used for calibration data.
  82. //
  83. NapProfilingData[0].NapLock = 0L;
  84. NapProfilingData[0].Calls = 0L;
  85. NapProfilingData[0].TimingErrors = 0L;
  86. NapProfilingData[0].TotalTime.HighPart = 0L;
  87. NapProfilingData[0].TotalTime.LowPart = 0L;
  88. NapProfilingData[0].FirstTime.HighPart = 0L;
  89. NapProfilingData[0].FirstTime.LowPart = 0L;
  90. NapProfilingData[0].MaxTime.HighPart = 0L;
  91. NapProfilingData[0].MaxTime.LowPart = 0L;
  92. NapProfilingData[0].MinTime.HighPart = MAX_LONG;
  93. NapProfilingData[0].MinTime.LowPart = MAX_ULONG;
  94. //
  95. // Clear the rest of the data collection area
  96. //
  97. NapClearData();
  98. //
  99. // Calibrate time overhead from profiling. We care mostly
  100. // about the minimum time here, to avoid extra time from
  101. // interrupts etc.
  102. //
  103. for (i=0; i<NUM_ITERATIONS; i++) {
  104. NapCalibrate();
  105. }
  106. }
  107. }
  108. }
  109. }
  110. NTSTATUS
  111. NapCreateDataSection(
  112. PNAPCONTROL *NapSectionPointer
  113. )
  114. /*++
  115. Routine Description:
  116. NapCreateData() is called to create the profiling data section.
  117. One section, named "\NapDataSection", is used for the whole system.
  118. It is accessible by anyone, so don't mess it up.
  119. Arguments:
  120. NapSectionPointer - a pointer to a pointer which will be set to
  121. to point to the beginning of the section.
  122. Return Value:
  123. Status
  124. --*/
  125. {
  126. NTSTATUS Status;
  127. HANDLE NapSectionHandle;
  128. HANDLE MyProcess;
  129. STRING NapSectionName;
  130. OBJECT_ATTRIBUTES ObjectAttributes;
  131. LARGE_INTEGER AllocationSize;
  132. ULONG ViewSize;
  133. PNAPCONTROL SectionPointer;
  134. //
  135. // Initialize object attributes for the dump file
  136. //
  137. NapSectionName.Length = 15;
  138. NapSectionName.MaximumLength = 15;
  139. NapSectionName.Buffer = "\\NapDataSection";
  140. ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
  141. ObjectAttributes.ObjectName = &NapSectionName;
  142. ObjectAttributes.RootDirectory = NULL;
  143. ObjectAttributes.SecurityDescriptor = NULL;
  144. ObjectAttributes.SecurityQualityOfService = NULL;
  145. ObjectAttributes.Attributes = OBJ_OPENIF |
  146. OBJ_CASE_INSENSITIVE;
  147. AllocationSize.HighPart = 0;
  148. AllocationSize.LowPart = (NAP_API_COUNT + 1) * sizeof(NAPDATA);
  149. Status = NtCreateSection(&NapSectionHandle,
  150. SECTION_MAP_READ |
  151. SECTION_MAP_WRITE,
  152. &ObjectAttributes,
  153. &AllocationSize,
  154. PAGE_READWRITE,
  155. SEC_COMMIT,
  156. NULL);
  157. if (NT_SUCCESS(Status)) {
  158. MyProcess = NtCurrentProcess();
  159. ViewSize = AllocationSize.LowPart;
  160. SectionPointer = NULL;
  161. Status = NtMapViewOfSection(NapSectionHandle,
  162. MyProcess,
  163. (PVOID *)&SectionPointer,
  164. 0,
  165. AllocationSize.LowPart,
  166. NULL,
  167. &ViewSize,
  168. ViewUnmap,
  169. MEM_TOP_DOWN,
  170. PAGE_READWRITE);
  171. *NapSectionPointer = SectionPointer;
  172. }
  173. return(Status);
  174. }
  175. VOID
  176. NapRecordInfo (
  177. IN ULONG ServiceNumber,
  178. IN LARGE_INTEGER Counters[]
  179. )
  180. /*++
  181. Routine Description:
  182. NapRecordInfo() is called after the API being measured has
  183. returned, and the value of the performance counter has been
  184. obtained.
  185. NOTE: Initialization occurs only once and is controlled by
  186. the NapInitDone global flag.
  187. Arguments:
  188. ServiceNumber - the number of the service being measured.
  189. -1 is reserved for calibration.
  190. Counters - a pointer to the value of the counter after the call
  191. to the measured routine. Followed immediately
  192. in memory by the value of the counter before the
  193. call to the measured routine.
  194. Return Value:
  195. None
  196. --*/
  197. {
  198. LARGE_INTEGER ElapsedTime;
  199. LARGE_INTEGER Difference;
  200. //
  201. // First make sure we have been initialized
  202. //
  203. if (NapControl != NULL) {
  204. //
  205. // Check to be sure profiling is not paused
  206. if (NapControl->Paused == 0) {
  207. //
  208. // Since ServiceNumber -1 is used for calibration, bump same
  209. // so indexes start at 0.
  210. //
  211. ServiceNumber++;
  212. //
  213. // Prevent others from changing data at the same time
  214. // we are.
  215. //
  216. NapAcquireSpinLock(&(NapProfilingData[ServiceNumber].NapLock));
  217. //
  218. // Record API info
  219. //
  220. NapProfilingData[ServiceNumber].Calls++;
  221. //
  222. // Elapsed time is end time minus start time
  223. //
  224. ElapsedTime =
  225. RtlLargeIntegerSubtract(Counters[0],Counters[1]);
  226. //
  227. // Now add elapsed time to total time
  228. //
  229. NapProfilingData[ServiceNumber].TotalTime =
  230. RtlLargeIntegerAdd(NapProfilingData[ServiceNumber].TotalTime,
  231. ElapsedTime);
  232. if (NapProfilingData[ServiceNumber].Calls == 1) {
  233. NapProfilingData[ServiceNumber].FirstTime = ElapsedTime;
  234. }
  235. else {
  236. Difference =
  237. RtlLargeIntegerSubtract(
  238. NapProfilingData[ServiceNumber].MaxTime,
  239. ElapsedTime);
  240. if (Difference.HighPart < 0) {
  241. //
  242. // A new maximum was attained
  243. //
  244. NapProfilingData[ServiceNumber].MaxTime = ElapsedTime;
  245. }
  246. Difference =
  247. RtlLargeIntegerSubtract(
  248. ElapsedTime,
  249. NapProfilingData[ServiceNumber].MinTime);
  250. if (Difference.HighPart < 0) {
  251. //
  252. // A new minimum was attained
  253. //
  254. NapProfilingData[ServiceNumber].MinTime = ElapsedTime;
  255. }
  256. }
  257. NapReleaseSpinLock(&(NapProfilingData[ServiceNumber].NapLock));
  258. }
  259. }
  260. }
  261. NTSTATUS
  262. NapClearData (
  263. VOID
  264. )
  265. /*++
  266. Routine Description:
  267. NapClearData() is called to clear all the counters and timers.
  268. The calibration counters are not cleared. For the rest,
  269. if not previously collected, the data will be lost.
  270. Arguments:
  271. None
  272. Return Value:
  273. Status
  274. --*/
  275. {
  276. ULONG ServiceNumber;
  277. //
  278. // Initialize the first one after the calibration data
  279. //
  280. NapAcquireSpinLock(&(NapProfilingData[1].NapLock));
  281. NapProfilingData[1].Calls = 0L;
  282. NapProfilingData[1].TimingErrors = 0L;
  283. NapProfilingData[1].TotalTime.HighPart = 0L;
  284. NapProfilingData[1].TotalTime.LowPart = 0L;
  285. NapProfilingData[1].FirstTime.HighPart = 0L;
  286. NapProfilingData[1].FirstTime.LowPart = 0L;
  287. NapProfilingData[1].MaxTime.HighPart = 0L;
  288. NapProfilingData[1].MaxTime.LowPart = 0L;
  289. NapProfilingData[1].MinTime.HighPart = MAX_LONG;
  290. NapProfilingData[1].MinTime.LowPart = MAX_ULONG;
  291. //
  292. // Now use the initialized first one to initialize the rest
  293. //
  294. for (ServiceNumber = 2; ServiceNumber <= NAP_API_COUNT; ServiceNumber++) {
  295. NapAcquireSpinLock(&(NapProfilingData[ServiceNumber].NapLock));
  296. NapProfilingData[ServiceNumber] = NapProfilingData[1];
  297. NapReleaseSpinLock(&(NapProfilingData[ServiceNumber].NapLock));
  298. }
  299. NapReleaseSpinLock(&(NapProfilingData[1].NapLock));
  300. return(STATUS_SUCCESS);
  301. }
  302. NTSTATUS
  303. NapRetrieveData (
  304. OUT NAPDATA *NapApiData,
  305. OUT PCHAR **NapApiNames,
  306. OUT PLARGE_INTEGER *NapCounterFrequency
  307. )
  308. /*++
  309. Routine Description:
  310. NapRetrieveData() is called to get all the relevant data
  311. about API's that have been profiled. It is wise to call
  312. NapPause() before calling this, and NapResume() afterwards.
  313. Can't just do these in here, 'cause you may be doing stuff outside
  314. of this call you don't want profiled.
  315. Arguments:
  316. NapApiData - a pointer to a buffer to which is copied
  317. the array of counters; must be large enough for
  318. NAP_API_COUNT+1; call NapGetApiCount to obtain needed
  319. size.
  320. NapApiNames - a pointer to which is copied a pointer to
  321. an array of pointers to API names
  322. NapCounterFrequency - a buffer to which is copied the frequency
  323. of the performance counter
  324. Return Value:
  325. Status
  326. --*/
  327. {
  328. ULONG ServiceNumber;
  329. *NapApiNames = NapNames;
  330. *NapCounterFrequency = &NapFrequency;
  331. for (ServiceNumber = 0; ServiceNumber <= NAP_API_COUNT; ServiceNumber++) {
  332. NapAcquireSpinLock(&(NapProfilingData[ServiceNumber].NapLock));
  333. NapApiData[ServiceNumber] = NapProfilingData[ServiceNumber];
  334. NapReleaseSpinLock(&(NapProfilingData[ServiceNumber].NapLock));
  335. NapReleaseSpinLock(&(NapApiData[ServiceNumber].NapLock));
  336. }
  337. return(STATUS_SUCCESS);
  338. }
  339. NTSTATUS
  340. NapGetApiCount (
  341. OUT PULONG NapApiCount
  342. )
  343. /*++
  344. Routine Description:
  345. NapGetApiCount() is called to get the number of API's which are
  346. being profiled. This can then be used to allocate an array for
  347. receiving the data from NapReturnData.
  348. Arguments:
  349. NapApiCount - A pointer throug which the count is returned.
  350. Return Value:
  351. Status
  352. --*/
  353. {
  354. *NapApiCount = NAP_API_COUNT;
  355. return(STATUS_SUCCESS);
  356. }
  357. NTSTATUS
  358. NapPause (
  359. VOID
  360. )
  361. /*++
  362. Routine Description:
  363. NapPause() is called to temporarily cease data collection.
  364. Data collection is resumed by a companion call to NapResume.
  365. Arguments:
  366. None
  367. Return Value:
  368. Status
  369. --*/
  370. {
  371. NapControl->Paused++;
  372. return(STATUS_SUCCESS);
  373. }
  374. NTSTATUS
  375. NapResume (
  376. VOID
  377. )
  378. /*++
  379. Routine Description:
  380. NapResume() is called to resume data collection after a companion
  381. call to NapPause.
  382. Arguments:
  383. None
  384. Return Value:
  385. Status
  386. --*/
  387. {
  388. NapControl->Paused--;
  389. return(STATUS_SUCCESS);
  390. }