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.

587 lines
16 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: PerfSnap.hxx
  7. //
  8. // Contents: Performace monitor. Snapshots system at user-defined time
  9. //
  10. // Classes: CPerfInfo, CPerformanceMonitor
  11. //
  12. // History: 30-Sep-93 KyleP Created
  13. //
  14. // Notes: These classes only do something interesting if PERFSNAP
  15. // is defined.
  16. //
  17. //--------------------------------------------------------------------------
  18. #if !defined(__PERFSNAP_HXX__)
  19. #define __PERFSNAP_HXX__
  20. #define USE_NEW_LARGE_INTEGERS
  21. extern "C"
  22. {
  23. #include <nt.h>
  24. #include <ntrtl.h>
  25. #include <nturtl.h>
  26. #ifdef NEVER
  27. #include <rpc.h>
  28. #include <rpcdce.h>
  29. #endif
  30. }
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <windows.h>
  34. #include <debnot.h>
  35. #include <heapstat.h>
  36. //+-------------------------------------------------------------------------
  37. //
  38. // Class: CPerfInfo
  39. //
  40. // Purpose: Holds snapshot of performance data
  41. //
  42. // History: 30-Sep-93 KyleP Created
  43. //
  44. //--------------------------------------------------------------------------
  45. #if defined(PERFSNAP)
  46. class CPerfInfo
  47. {
  48. public:
  49. inline void Init(char const * pszTitle, int const level);
  50. inline CPerfInfo & operator -(CPerfInfo const & piIn);
  51. inline void Comment(FILE * pfOut,
  52. char const * pszComment,
  53. LARGE_INTEGER stime);
  54. inline void Print(FILE * pfOut, LARGE_INTEGER stime);
  55. inline void _Print(FILE * pfOut);
  56. inline static void PrintHeader(FILE * pfOut);
  57. private:
  58. enum
  59. {
  60. _cbProcPerfXfer = 100 * sizeof(SYSTEM_PROCESS_INFORMATION) +
  61. 500 * sizeof(SYSTEM_THREAD_INFORMATION)
  62. };
  63. static unsigned char _ProcPerfXfer[_cbProcPerfXfer];
  64. int _level;
  65. char _szTitle[100];
  66. LARGE_INTEGER _time;
  67. SYSTEM_PERFORMANCE_INFORMATION _SysPerf;
  68. SYSTEM_PROCESS_INFORMATION _ProcPerf;
  69. HEAPSTATS _heapStats;
  70. #ifdef NEVER
  71. // DO NOT SEPARATE
  72. RPC_STATS_VECTOR _rpcStats;
  73. long _rpcExtraSpace[3];
  74. // END OF DO NOT SEPARATE
  75. #endif
  76. };
  77. # define IMPLEMENT_PERFSNAP() \
  78. unsigned char CPerfInfo::_ProcPerfXfer[CPerfInfo::_cbProcPerfXfer];
  79. #else // PERFSNAP
  80. # define IMPLEMENT_PERFSNAP()
  81. #endif // PERFSNAP
  82. //+-------------------------------------------------------------------------
  83. //
  84. // Class: CPerformanceMonitor
  85. //
  86. // Purpose: Monitor performance of system/process at user-defined time.
  87. //
  88. // History: 30-Sep-93 KyleP Created
  89. //
  90. //--------------------------------------------------------------------------
  91. class CPerformanceMonitor
  92. {
  93. public:
  94. inline CPerformanceMonitor(char const * szFile = 0);
  95. inline ~CPerformanceMonitor();
  96. inline void PrintHeader();
  97. inline void Comment(char const * pszComment);
  98. inline void Snap(char const * pszTitle, int const level);
  99. inline void Delta(char const * pszTitle, int const level);
  100. #if defined(PERFSNAP)
  101. private:
  102. FILE * _pfOut;
  103. int _iLastSnap;
  104. LARGE_INTEGER _time;
  105. CPerfInfo _aSnap[2];
  106. #endif // PERFSNAP
  107. };
  108. inline CPerformanceMonitor::CPerformanceMonitor(char const * szFile)
  109. {
  110. #if defined(PERFSNAP)
  111. NtQuerySystemTime(&_time); // start time
  112. _iLastSnap = 0;
  113. if (szFile)
  114. _pfOut = fopen(szFile, "a");
  115. else
  116. _pfOut = stdout;
  117. fprintf(_pfOut, "\n----------------------------------------\n");
  118. _aSnap[0].Init("Start0", 0);
  119. _aSnap[1].Init("Start1", 0);
  120. #endif // PERFSNAP
  121. }
  122. inline CPerformanceMonitor::~CPerformanceMonitor()
  123. {
  124. #if defined(PERFSNAP)
  125. fclose(_pfOut);
  126. #endif // PERFSNAP
  127. }
  128. inline void CPerformanceMonitor::PrintHeader()
  129. {
  130. #if defined(PERFSNAP)
  131. _aSnap[0].PrintHeader(_pfOut);
  132. #endif // PERFSNAP
  133. }
  134. inline void CPerformanceMonitor::Comment(char const * pszComment)
  135. {
  136. #if defined(PERFSNAP)
  137. _aSnap[_iLastSnap].Comment(_pfOut, pszComment, _time);
  138. #endif // PERFSNAP
  139. }
  140. inline void CPerformanceMonitor::Snap(char const * pszTitle, int const level)
  141. {
  142. #if defined(PERFSNAP)
  143. _iLastSnap = (_iLastSnap + 1) % 2;
  144. _aSnap[_iLastSnap].Init(pszTitle, level);
  145. _aSnap[_iLastSnap].Print(_pfOut, _time);
  146. #endif // PERFSNAP
  147. }
  148. inline void CPerformanceMonitor::Delta(char const * pszTitle, int const level)
  149. {
  150. #if defined(PERFSNAP)
  151. _iLastSnap = (_iLastSnap + 1) % 2;
  152. _aSnap[_iLastSnap].Init(pszTitle, level);
  153. CPerfInfo piDelta = _aSnap[_iLastSnap] - _aSnap[(_iLastSnap + 1) % 2];
  154. // _aSnap[_iLastSnap].Print(_pfOut, _time);
  155. piDelta.Print(_pfOut, _time);
  156. #endif // PERFSNAP
  157. }
  158. #if defined(PERFSNAP)
  159. inline void CPerfInfo::Init(char const * pszTitle, int const level)
  160. {
  161. //
  162. // Get time
  163. //
  164. NtQuerySystemTime(&_time);
  165. //
  166. // Set level
  167. //
  168. _level = level;
  169. //
  170. // Copy title string
  171. //
  172. int len = strlen(pszTitle);
  173. if (len > sizeof(_szTitle) - 1)
  174. len = sizeof(_szTitle) - 1;
  175. memcpy(_szTitle, pszTitle, len);
  176. _szTitle[len] = 0;
  177. //
  178. // Get performance information
  179. //
  180. NTSTATUS Status = NtQuerySystemInformation (SystemPerformanceInformation,
  181. &_SysPerf,
  182. sizeof(_SysPerf),
  183. 0);
  184. Win4Assert(NT_SUCCESS(Status));
  185. //
  186. // Process info. Comes back for *all* processes and threads!
  187. //
  188. Status = NtQuerySystemInformation (SystemProcessInformation,
  189. _ProcPerfXfer,
  190. _cbProcPerfXfer,
  191. 0);
  192. Win4Assert(NT_SUCCESS(Status));
  193. //
  194. // Find the process we care about and copy it out.
  195. //
  196. HANDLE pid = (HANDLE)NtCurrentTeb()->ClientId.UniqueProcess;
  197. unsigned char * pb = _ProcPerfXfer;
  198. while (TRUE)
  199. {
  200. SYSTEM_PROCESS_INFORMATION * pProc = (SYSTEM_PROCESS_INFORMATION *)pb;
  201. if (pProc->UniqueProcessId == pid)
  202. {
  203. memcpy(&_ProcPerf, pProc, sizeof(SYSTEM_PROCESS_INFORMATION));
  204. break;
  205. }
  206. if (pProc->NextEntryOffset == 0)
  207. {
  208. printf("Couldn't find info for process 0x%x\n", pid);
  209. break;
  210. }
  211. pb += pProc->NextEntryOffset;
  212. }
  213. #ifdef NEVER
  214. //
  215. // RPC Statistics
  216. //
  217. RPC_STATS_VECTOR *pStats;
  218. RpcMgmtInqStats(NULL, &pStats);
  219. memcpy(& _rpcStats, pStats, sizeof(_rpcStats) + sizeof(_rpcExtraSpace));
  220. RpcMgmtStatsVectorFree(&pStats);
  221. #endif
  222. //
  223. // (Cairo) Heap Statistics
  224. //
  225. GetHeapStats(&_heapStats);
  226. }
  227. inline CPerfInfo & CPerfInfo::operator -(CPerfInfo const & pi2)
  228. {
  229. CPerfInfo ret;
  230. //
  231. // Make a delta title
  232. //
  233. unsigned len = strlen(_szTitle);
  234. memcpy(ret._szTitle, _szTitle, len);
  235. if (len < sizeof(ret._szTitle)-4)
  236. {
  237. memcpy(ret._szTitle + len, " - ", 4);
  238. len += 3;
  239. }
  240. unsigned len2 = strlen(pi2._szTitle);
  241. if (len2 > sizeof(ret._szTitle) - len - 1)
  242. len2 = sizeof(ret._szTitle) - len - 1;
  243. memcpy(ret._szTitle + len, pi2._szTitle, len2);
  244. ret._szTitle[len+len2] = 0;
  245. ret._time = _time - pi2._time;
  246. //
  247. // 'Subtract' performance info
  248. //
  249. ret._SysPerf.AvailablePages = _SysPerf.AvailablePages -
  250. pi2._SysPerf.AvailablePages;
  251. ret._SysPerf.CommittedPages = _SysPerf.CommittedPages -
  252. pi2._SysPerf.CommittedPages;
  253. ret._SysPerf.PeakCommitment = max(_SysPerf.PeakCommitment,
  254. pi2._SysPerf.PeakCommitment);
  255. ret._SysPerf.PageFaultCount = _SysPerf.PageFaultCount -
  256. pi2._SysPerf.PageFaultCount;
  257. ret._SysPerf.PagedPoolPages = _SysPerf.PagedPoolPages -
  258. pi2._SysPerf.PagedPoolPages;
  259. ret._SysPerf.NonPagedPoolPages = _SysPerf.NonPagedPoolPages -
  260. pi2._SysPerf.NonPagedPoolPages;
  261. //
  262. // System/LPC calls
  263. //
  264. ret._SysPerf.SystemCalls = _SysPerf.SystemCalls - pi2._SysPerf.SystemCalls;
  265. #ifdef NEVER
  266. ret._SysPerf.LpcCallOperationCount = _SysPerf.LpcCallOperationCount -
  267. pi2._SysPerf.LpcCallOperationCount;
  268. //
  269. // RPC
  270. //
  271. for (int i = 0; i < 4; i++)
  272. ret._rpcStats.Stats[i] = _rpcStats.Stats[i] - pi2._rpcStats.Stats[i];
  273. #endif
  274. //
  275. // CPU time
  276. //
  277. ret._ProcPerf.UserTime = _ProcPerf.UserTime - pi2._ProcPerf.UserTime;
  278. ret._ProcPerf.KernelTime = _ProcPerf.KernelTime - pi2._ProcPerf.KernelTime;
  279. //
  280. // Memory
  281. //
  282. ret._ProcPerf.PagefileUsage = _ProcPerf.PagefileUsage -
  283. pi2._ProcPerf.PagefileUsage;
  284. ret._ProcPerf.PeakPagefileUsage = max(_ProcPerf.PeakPagefileUsage,
  285. pi2._ProcPerf.PeakPagefileUsage);
  286. ret._ProcPerf.PrivatePageCount = _ProcPerf.PrivatePageCount -
  287. pi2._ProcPerf.PrivatePageCount;
  288. ret._ProcPerf.QuotaPagedPoolUsage = _ProcPerf.QuotaPagedPoolUsage -
  289. pi2._ProcPerf.QuotaPagedPoolUsage;
  290. ret._ProcPerf.QuotaNonPagedPoolUsage = _ProcPerf.QuotaNonPagedPoolUsage -
  291. pi2._ProcPerf.QuotaNonPagedPoolUsage;
  292. ret._ProcPerf.PeakWorkingSetSize = max(_ProcPerf.PeakWorkingSetSize,
  293. pi2._ProcPerf.PeakWorkingSetSize);
  294. ret._ProcPerf.WorkingSetSize = _ProcPerf.WorkingSetSize -
  295. pi2._ProcPerf.WorkingSetSize;
  296. //
  297. // Threads
  298. //
  299. ret._ProcPerf.NumberOfThreads = _ProcPerf.NumberOfThreads - pi2._ProcPerf.NumberOfThreads;
  300. ret._ProcPerf.NumberOfThreads;
  301. //
  302. // (Cairo) Heap Stats
  303. //
  304. ret._heapStats.cNew =_heapStats.cNew -pi2._heapStats.cNew;
  305. ret._heapStats.cZeroNew =_heapStats.cZeroNew -pi2._heapStats.cZeroNew;
  306. ret._heapStats.cDelete =_heapStats.cDelete -pi2._heapStats.cDelete;
  307. ret._heapStats.cZeroDelete=_heapStats.cZeroDelete -
  308. pi2._heapStats.cZeroDelete;
  309. ret._heapStats.cRealloc =_heapStats.cRealloc -pi2._heapStats.cRealloc;
  310. ret._heapStats.cbNewed =_heapStats.cbNewed -pi2._heapStats.cbNewed;
  311. ret._heapStats.cbDeleted =_heapStats.cbDeleted-pi2._heapStats.cbDeleted;
  312. return(ret);
  313. }
  314. inline void CPerfInfo::PrintHeader(FILE * pfOut)
  315. {
  316. LARGE_INTEGER time;
  317. SYSTEMTIME systime;
  318. NtQuerySystemTime(&time);
  319. FileTimeToSystemTime((FILETIME *)&time, &systime);
  320. fprintf(pfOut,
  321. "Performance Run %02d/%02d/%02d %02d:%02d:%02d\n",
  322. systime.wMonth, systime.wDay, systime.wYear,
  323. systime.wHour, systime.wMinute, systime.wSecond);
  324. fprintf(pfOut,
  325. "Abs/Rel\t"
  326. "Level\t"
  327. "System Time\t"
  328. "System Time ms\t"
  329. "Title\t"
  330. "Physical Memory Available Kb\t"
  331. "Virtual Memory Committed Kb\t"
  332. "Virtual Memory Max Committed Kb\t"
  333. "Virtual Memory Page Faults\t"
  334. "System Total Paged Pool Kb\t"
  335. "System Total Nonpaged Pool Kb\t"
  336. "System Calls\t"
  337. "Process User CPU Time ms\t"
  338. "Process Kernel CPU Time ms\t"
  339. "Process Page File Used pages\t"
  340. "Process Page File Max Used pages\t"
  341. "Process Page File Private pages\t"
  342. "Process Paged Pool pages\t"
  343. "Process Nonpaged Pool pages\t"
  344. "Process #Threads\t"
  345. "Working Set Peak Kb\t"
  346. "Working Set Current Kb\t"
  347. "Heap Allocs\t"
  348. "0-len Heap Allocs\t"
  349. "Heap Deletes\t"
  350. "0-len Heap Deletes\t"
  351. "Heap Reallocs\t"
  352. "Heap Allocated bytes\t"
  353. "Heap Freed bytes\t"
  354. "Process ID\t"
  355. "Thread ID\t"
  356. "Time To Snap ms\t"
  357. "System Time ms absolute\n");
  358. }
  359. inline void CPerfInfo::_Print(FILE * pfOut)
  360. {
  361. // LPCCallOperationsCount not printed: its bogus
  362. // _rpcStats[0..3] not printed: never non-zero
  363. // "RPC Calls In\tRPC Calls Out\tRPC Packets In\tRPC Packets Out\t"
  364. fprintf(pfOut,
  365. "%ld\t"
  366. "%ld\t"
  367. "%ld\t"
  368. "%lu\t"
  369. "%ld\t"
  370. "%ld\t"
  371. "%lu\t"
  372. "%lu\t"
  373. "%lu\t"
  374. "%ld\t"
  375. "%ld\t"
  376. "%ld\t"
  377. "%ld\t"
  378. "%ld\t"
  379. "%ld\t"
  380. "%ld\t"
  381. "%ld\t"
  382. "%lu\t"
  383. "%lu\t"
  384. "%lu\t"
  385. "%lu\t"
  386. "%lu\t"
  387. "%lu\t"
  388. "%lu\t"
  389. "%ld\t"
  390. "%ld",
  391. _SysPerf.AvailablePages * 4,
  392. _SysPerf.CommittedPages * 4,
  393. _SysPerf.PeakCommitment * 4,
  394. _SysPerf.PageFaultCount,
  395. _SysPerf.PagedPoolPages * 4,
  396. _SysPerf.NonPagedPoolPages * 4,
  397. _SysPerf.SystemCalls,
  398. (_ProcPerf.UserTime.LowPart+5000) / 10000,
  399. (_ProcPerf.KernelTime.LowPart+5000) / 10000,
  400. (_ProcPerf.PagefileUsage+1023) / 1024,
  401. (_ProcPerf.PeakPagefileUsage+1023) / 1024,
  402. (_ProcPerf.PrivatePageCount+1023) / 1024,
  403. (_ProcPerf.QuotaPagedPoolUsage+1023) / 1024,
  404. (_ProcPerf.QuotaNonPagedPoolUsage+1023) / 1024,
  405. _ProcPerf.NumberOfThreads,
  406. (_ProcPerf.PeakWorkingSetSize+1023) / 1024,
  407. (_ProcPerf.WorkingSetSize+1023) / 1024,
  408. _heapStats.cNew,
  409. _heapStats.cZeroNew,
  410. _heapStats.cDelete,
  411. _heapStats.cZeroDelete,
  412. _heapStats.cRealloc,
  413. _heapStats.cbNewed,
  414. _heapStats.cbDeleted,
  415. GetCurrentProcessId(),
  416. GetCurrentThreadId()
  417. );
  418. }
  419. #define CVT_TO_MS(t) (((t.wHour*60 + t.wMinute)*60 + t.wSecond)*1000 + t.wMilliseconds)
  420. inline void CPerfInfo::Print(FILE * pfOut, LARGE_INTEGER stime)
  421. {
  422. LARGE_INTEGER time;
  423. LARGE_INTEGER dtime;
  424. SYSTEMTIME systime;
  425. _szTitle[sizeof(_szTitle)-1] = '\0';
  426. //
  427. // Time is either a delta or absolute.
  428. //
  429. if (_time.HighPart > 0)
  430. {
  431. SYSTEMTIME systime;
  432. FileTimeToSystemTime((FILETIME *)&_time, &systime);
  433. dtime = _time - stime;
  434. fprintf(pfOut,
  435. "A\t%d\t%02d:%02d:%02d.%03d\t%u\t%s\t",
  436. _level,
  437. systime.wHour, systime.wMinute, systime.wSecond,
  438. systime.wMilliseconds,
  439. dtime.LowPart / 10000,
  440. _szTitle);
  441. }
  442. else
  443. {
  444. // FILETIME is in units of 100 nanoseconds (== 0.1 ms)
  445. fprintf(pfOut,
  446. "R\t%d\t\t%u\t%s\t",
  447. _level,
  448. _time.LowPart / 10000,
  449. _szTitle);
  450. }
  451. _Print(pfOut);
  452. // A FILETIME is in units of 100 nanoseconds (== 0.1 ms)
  453. NtQuerySystemTime(&time);
  454. dtime = time - _time;
  455. FileTimeToSystemTime((FILETIME*)&_time, &systime);
  456. fprintf(pfOut, "\t%d\t%d\n", dtime.LowPart / 10000, CVT_TO_MS(systime));
  457. }
  458. inline void CPerfInfo::Comment(FILE * pfOut, char const * pszComment,
  459. LARGE_INTEGER stime)
  460. {
  461. SYSTEMTIME systod;
  462. LARGE_INTEGER time;
  463. LARGE_INTEGER tod;
  464. LARGE_INTEGER dtime;
  465. NtQuerySystemTime(&tod);
  466. FileTimeToSystemTime((FILETIME*)&tod, &systod);
  467. dtime = tod - stime;
  468. fprintf(pfOut, "C\t0\t%02d:%02d:%02d.%03d\t%d\t%s\t",
  469. systod.wHour, systod.wMinute, systod.wSecond,
  470. systod.wMilliseconds,
  471. dtime.LowPart / 10000,
  472. pszComment);
  473. _Print(pfOut);
  474. NtQuerySystemTime(&time);
  475. dtime = time - tod;
  476. fprintf(pfOut, "\t%d\t%d\n", dtime.LowPart / 10000, CVT_TO_MS(systod));
  477. }
  478. #endif // PERFSNAP
  479. #endif // __PERFSNAP_HXX__