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.

1891 lines
49 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // TaskMan - NT TaskManager
  4. // Copyright (C) Microsoft
  5. //
  6. // File: perfpage.cpp
  7. //
  8. // History: Nov-10-95 DavePl Created
  9. //
  10. //--------------------------------------------------------------------------
  11. #include "precomp.h"
  12. #define GRAPH_BRUSH BLACK_BRUSH
  13. #define GRAPH_LINE_COLOR RGB(0, 128, 64)
  14. #define GRAPH_TEXT_COLOR RGB(0, 255, 0)
  15. #define STRIP_HEIGHT 75
  16. #define STRIP_WIDTH 33
  17. LARGE_INTEGER PreviousCPUIdleTime[MAXIMUM_PROCESSORS] = {0 ,0};
  18. LARGE_INTEGER PreviousCPUTotalTime[MAXIMUM_PROCESSORS] = {0 ,0};
  19. LARGE_INTEGER PreviousCPUKernelTime[MAXIMUM_PROCESSORS] = {0 ,0};
  20. LPBYTE g_pCPUHistory[MAXIMUM_PROCESSORS] = { NULL };
  21. LPBYTE g_pKernelHistory[MAXIMUM_PROCESSORS] = { NULL };
  22. LPBYTE g_pMEMHistory = NULL;
  23. BYTE g_CPUUsage = 0;
  24. BYTE g_KernelUsage = 0;
  25. __int64 g_MEMUsage = 0;
  26. __int64 g_MEMMax = 0;
  27. DWORD g_PageSize;
  28. /*++ CPerfPage::SizePerfPage
  29. Routine Description:
  30. Sizes its children based on the size of the
  31. tab control on which it appears.
  32. Arguments:
  33. Return Value:
  34. Revision History:
  35. Nov-12-95 Davepl Created
  36. --*/
  37. static const INT aPerfControls[] =
  38. {
  39. IDC_STATIC1,
  40. IDC_STATIC2,
  41. IDC_STATIC3,
  42. IDC_STATIC4,
  43. IDC_STATIC5,
  44. IDC_STATIC6,
  45. IDC_STATIC8,
  46. IDC_STATIC9,
  47. IDC_STATIC10,
  48. IDC_STATIC11,
  49. IDC_STATIC12,
  50. IDC_STATIC13,
  51. IDC_STATIC14,
  52. IDC_STATIC15,
  53. IDC_STATIC16,
  54. IDC_STATIC17,
  55. IDC_TOTAL_PHYSICAL,
  56. IDC_AVAIL_PHYSICAL,
  57. IDC_FILE_CACHE,
  58. IDC_COMMIT_TOTAL,
  59. IDC_COMMIT_LIMIT,
  60. IDC_COMMIT_PEAK,
  61. IDC_KERNEL_TOTAL,
  62. IDC_KERNEL_PAGED,
  63. IDC_KERNEL_NONPAGED,
  64. IDC_TOTAL_HANDLES,
  65. IDC_TOTAL_THREADS,
  66. IDC_TOTAL_PROCESSES,
  67. };
  68. // Amount of spacing down from the top of a group box to the
  69. // control it contains
  70. void CPerfPage::SizePerfPage()
  71. {
  72. // Get the coords of the tab control
  73. RECT rcParent;
  74. if (g_Options.m_fNoTitle)
  75. {
  76. GetClientRect(g_hMainWnd, &rcParent);
  77. }
  78. else
  79. {
  80. GetClientRect(m_hwndTabs, &rcParent);
  81. MapWindowPoints(m_hwndTabs, m_hPage, (LPPOINT) &rcParent, 2);
  82. TabCtrl_AdjustRect(m_hwndTabs, FALSE, &rcParent);
  83. }
  84. // We have N panes, where N is 1 or g_cProcessors depending on what mode the
  85. // cpu meter is currently in
  86. INT cPanes = (CM_PANES == g_Options.m_cmHistMode) ? g_cProcessors : 1;
  87. HDWP hdwp = BeginDeferWindowPos( 7 + ARRAYSIZE(aPerfControls) + cPanes );
  88. if (!hdwp)
  89. return;
  90. // Calc the deltas in the x and y positions that we need to
  91. // move each of the child controls
  92. RECT rcMaster;
  93. HWND hwndMaster = GetDlgItem(m_hPage, IDC_STATIC5);
  94. GetWindowRect(hwndMaster, &rcMaster);
  95. MapWindowPoints(HWND_DESKTOP, m_hPage, (LPPOINT) &rcMaster, 2);
  96. INT dy = ((rcParent.bottom - g_DefSpacing * 2) - rcMaster.bottom);
  97. // Move each of the child controls by the above delta
  98. for (int i = 0; i < ARRAYSIZE(aPerfControls); i++)
  99. {
  100. HWND hwndCtrl = GetDlgItem(m_hPage, aPerfControls[i]);
  101. RECT rcCtrl;
  102. GetWindowRect(hwndCtrl, &rcCtrl);
  103. MapWindowPoints(HWND_DESKTOP, m_hPage, (LPPOINT) &rcCtrl, 2);
  104. DeferWindowPos(hdwp, hwndCtrl, NULL,
  105. rcCtrl.left,
  106. rcCtrl.top + dy,
  107. 0, 0,
  108. SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  109. }
  110. HWND hwndTopFrame = GetDlgItem(m_hPage, IDC_STATIC13);
  111. RECT rcTopFrame;
  112. GetWindowRect(hwndTopFrame, &rcTopFrame);
  113. MapWindowPoints(HWND_DESKTOP, m_hPage, (LPPOINT) &rcTopFrame, 2);
  114. INT yTop = rcTopFrame.top + dy;
  115. INT yHist;
  116. if (g_Options.m_fNoTitle)
  117. {
  118. yHist = rcParent.bottom - rcParent.top - g_DefSpacing * 2;
  119. }
  120. else
  121. {
  122. yHist = (yTop - g_DefSpacing * 3) / 2;
  123. }
  124. // Size the CPU history frame
  125. RECT rcFrame;
  126. HWND hwndFrame = GetDlgItem(m_hPage, IDC_CPUFRAME);
  127. GetWindowRect(hwndFrame, &rcFrame);
  128. MapWindowPoints(NULL, m_hPage, (LPPOINT) &rcFrame, 2);
  129. DeferWindowPos(hdwp, hwndFrame, NULL, 0, 0,
  130. (rcParent.right - rcFrame.left) - g_DefSpacing * 2,
  131. yHist,
  132. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  133. // Size the CPU bar graph frame
  134. RECT rcCPUFrame;
  135. HWND hwndCPUFrame = GetDlgItem(m_hPage, IDC_STATIC);
  136. GetWindowRect(hwndCPUFrame, &rcCPUFrame);
  137. MapWindowPoints(NULL, m_hPage, (LPPOINT) &rcCPUFrame, 2);
  138. DeferWindowPos(hdwp, hwndCPUFrame, NULL, 0, 0,
  139. (rcCPUFrame.right - rcCPUFrame.left),
  140. yHist,
  141. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  142. RECT rcCPUBAR;
  143. HWND hwndCPUBAR = GetDlgItem(m_hPage, IDC_CPUMETER);
  144. GetWindowRect(hwndCPUBAR, &rcCPUBAR);
  145. MapWindowPoints(NULL, m_hPage, (LPPOINT) &rcCPUBAR, 2);
  146. DeferWindowPos(hdwp, hwndCPUBAR, NULL, rcCPUFrame.left + g_InnerSpacing * 2, rcCPUFrame.top + g_TopSpacing,
  147. (rcCPUBAR.right - rcCPUBAR.left),
  148. yHist - g_TopSpacing - g_InnerSpacing * 2 ,
  149. SWP_NOZORDER | SWP_NOACTIVATE);
  150. // Size the mem bar graph frame
  151. RECT rcMEMFrame;
  152. HWND hwndMEMFrame = GetDlgItem(m_hPage, IDC_MEMBARFRAME);
  153. GetWindowRect(hwndMEMFrame, &rcMEMFrame);
  154. MapWindowPoints(NULL, m_hPage, (LPPOINT) &rcMEMFrame, 2);
  155. DeferWindowPos(hdwp, hwndMEMFrame, NULL, rcMEMFrame.left, yHist + g_DefSpacing * 2,
  156. (rcMEMFrame.right - rcMEMFrame.left),
  157. yHist,
  158. SWP_NOZORDER | SWP_NOACTIVATE);
  159. RECT rcMEMBAR;
  160. HWND hwndMEMBAR = GetDlgItem(m_hPage, IDC_MEMMETER);
  161. GetWindowRect(hwndMEMBAR, &rcMEMBAR);
  162. MapWindowPoints(NULL, m_hPage, (LPPOINT) &rcMEMBAR, 2);
  163. DeferWindowPos(hdwp, hwndMEMBAR, NULL, rcMEMBAR.left, yHist + g_DefSpacing * 2 + g_TopSpacing,
  164. (rcMEMBAR.right - rcMEMBAR.left),
  165. yHist - g_InnerSpacing * 2 - g_TopSpacing,
  166. SWP_NOZORDER | SWP_NOACTIVATE);
  167. // Size the Memory history frame
  168. RECT rcMemFrame;
  169. HWND hwndMemFrame = GetDlgItem(m_hPage, IDC_MEMFRAME);
  170. GetWindowRect(hwndMemFrame, &rcMemFrame);
  171. MapWindowPoints(NULL, m_hPage, (LPPOINT) &rcMemFrame, 2);
  172. DeferWindowPos(hdwp, hwndMemFrame, NULL, rcMemFrame.left, yHist + g_DefSpacing * 2,
  173. (rcParent.right - rcMemFrame.left) - g_DefSpacing * 2,
  174. yHist,
  175. SWP_NOZORDER | SWP_NOACTIVATE);
  176. // Total amount of room available for all of the panes
  177. INT Width = (rcParent.right - rcParent.left) - (rcFrame.left - rcParent.left) - g_DefSpacing * 2
  178. - g_InnerSpacing * 3;
  179. // Use this width to size the memory graph
  180. HWND hwndButton = GetDlgItem(m_hPage, IDC_MEMGRAPH);
  181. RECT rcButton;
  182. GetWindowRect(hwndButton, &rcButton);
  183. MapWindowPoints(NULL, m_hPage, (LPPOINT) &rcButton, 2);
  184. DeferWindowPos(hdwp, hwndButton, NULL, rcFrame.left + g_InnerSpacing * 2,
  185. yHist + g_DefSpacing * 2 + g_TopSpacing,
  186. Width - g_InnerSpacing,
  187. yHist - g_InnerSpacing * 2 - g_TopSpacing,
  188. SWP_NOZORDER | SWP_NOACTIVATE);
  189. // Total amount of room available for each CPU pane
  190. Width -= ( cPanes < 16 ? cPanes : 16 ) * g_InnerSpacing;
  191. Width /= ( cPanes < 16 ? cPanes : 16 );
  192. Width = Width >= 0 ? Width : 0;
  193. INT Height = ( yHist - g_InnerSpacing * 2 - g_TopSpacing ) / ( ( cPanes % 16 != 0 ? 1 : 0 ) + ( cPanes / 16 ) );
  194. for (i = 0; i < cPanes; i++)
  195. {
  196. HWND hwnd = GetDlgItem(m_hPage, IDC_CPUGRAPH + i);
  197. if ( NULL != hwnd )
  198. {
  199. INT left = rcFrame.left + g_InnerSpacing * ( ( i % 16 ) + 2) + Width * ( i % 16 );
  200. INT top = rcFrame.top + g_TopSpacing + Height * ( i / 16 );
  201. DeferWindowPos( hdwp, hwnd, NULL, left, top, Width, Height, 0 );
  202. }
  203. }
  204. // Create new bitmaps to be used in the history windows
  205. EndDeferWindowPos(hdwp);
  206. GetClientRect(hwndButton, &rcButton);
  207. FreeMemoryBitmaps(); // Free any old ones
  208. CreateMemoryBitmaps(rcButton.right - rcButton.left, rcButton.bottom - rcButton.top);
  209. }
  210. /*++ CPerfPage::CreatePens
  211. Routine Description:
  212. Creates 8 different colors pens, saves them in
  213. the pen array
  214. Arguments:
  215. Return Value:
  216. Revision History:
  217. Nov-12-95 Davepl Created
  218. --*/
  219. static const COLORREF aColors[] =
  220. {
  221. RGB(000, 255, 000),
  222. RGB(255, 000, 000),
  223. RGB(255, 000, 255),
  224. RGB(000, 000, 255),
  225. RGB(000, 255, 255),
  226. RGB(255, 128, 000),
  227. RGB(255, 000, 255),
  228. RGB(000, 128, 255),
  229. // End of CPU pens
  230. #define MEM_PEN 8
  231. RGB(255, 255, 0),
  232. };
  233. //
  234. //
  235. //
  236. void CPerfPage::CreatePens()
  237. {
  238. for (int i = 0; i < ARRAYSIZE(aColors); i++)
  239. {
  240. // Create then pen. If a failure occurs, just substitute
  241. // the white pen
  242. m_hPens[i] = CreatePen(PS_SOLID, 1, aColors[i]);
  243. if (NULL == m_hPens[i])
  244. {
  245. m_hPens[i] = (HPEN) GetStockObject(WHITE_PEN);
  246. }
  247. }
  248. }
  249. //
  250. //
  251. //
  252. void CPerfPage::ReleasePens()
  253. {
  254. for (int i = 0; i < NUM_PENS; i++)
  255. {
  256. if (m_hPens[i])
  257. {
  258. DeleteObject(m_hPens[i]);
  259. }
  260. }
  261. }
  262. /*++ CPerfPage::DrawGraphPaper
  263. Routine Description:
  264. Draws a graph-paper-like grid into a memory bitmap
  265. Arguments:
  266. hdcGraph - HDC to draw into
  267. prcGraph - RECT describing area to draw
  268. Width - Amount, on right side, to actually draw
  269. Revision History:
  270. Jan-17-95 Davepl Created
  271. --*/
  272. static int g_Scrollamount = 0;
  273. void DrawGraphPaper(HDC hdcGraph, RECT * prcGraph, int Width)
  274. {
  275. #define GRAPHPAPERSIZE 12
  276. int Leftside = prcGraph->right - Width;
  277. // Only one of the many graphs needs to ask us to scroll
  278. HPEN hPen = CreatePen(PS_SOLID, 1, GRAPH_LINE_COLOR);
  279. HGDIOBJ hOld = SelectObject(hdcGraph, hPen);
  280. for (int i = GRAPHPAPERSIZE - 1; i < prcGraph->bottom - prcGraph->top; i+= GRAPHPAPERSIZE)
  281. {
  282. MoveToEx(hdcGraph,
  283. Leftside,
  284. i + prcGraph->top,
  285. (LPPOINT) NULL);
  286. LineTo(hdcGraph,
  287. prcGraph->right,
  288. i + prcGraph->top);
  289. }
  290. for (i = prcGraph->right - g_Scrollamount; i > Leftside; i -= GRAPHPAPERSIZE)
  291. {
  292. MoveToEx(hdcGraph,
  293. i,
  294. prcGraph->top,
  295. (LPPOINT) NULL);
  296. LineTo(hdcGraph,
  297. i,
  298. prcGraph->bottom);
  299. }
  300. if (hOld)
  301. {
  302. SelectObject(hdcGraph, hOld);
  303. }
  304. DeleteObject(hPen);
  305. }
  306. /*++ CPerfPage::DrawCPUGraph
  307. Routine Description:
  308. Draws the CPU graph (which is an ownerdraw control)
  309. Arguments:
  310. lpdi - LPDRAWITEMSTRUCT describing area we need to paint
  311. iPane - Pane number to be drawn (ie: which CPU)
  312. Return Value:
  313. Revision History:
  314. Nov-12-95 Davepl Created
  315. --*/
  316. void CPerfPage::DrawCPUGraph(LPDRAWITEMSTRUCT lpdi, UINT iPane)
  317. {
  318. #define THISCPU 0
  319. if (NULL == m_hdcGraph)
  320. {
  321. return;
  322. }
  323. FillRect(m_hdcGraph, &m_rcGraph, (HBRUSH) GetStockObject(GRAPH_BRUSH));
  324. int Width = lpdi->rcItem.right - lpdi->rcItem.left;
  325. int Scale = (Width - 1) / HIST_SIZE;
  326. if (0 == Scale)
  327. {
  328. Scale = 2;
  329. }
  330. //
  331. // Draw the CPU history graph
  332. //
  333. DrawGraphPaper(m_hdcGraph, &m_rcGraph, Width);
  334. INT cPanes = (CM_PANES == g_Options.m_cmHistMode) ? g_cProcessors : 1;
  335. int GraphHeight = ( m_rcGraph.bottom - m_rcGraph.top - 1 ) / ( ( cPanes % 16 != 0 ? 1 : 0 ) + ( cPanes / 16 ) );;
  336. if (g_Options.m_cmHistMode == CM_PANES)
  337. {
  338. //
  339. // Draw the kernel times
  340. //
  341. if (g_Options.m_fKernelTimes)
  342. {
  343. HGDIOBJ hOld = SelectObject(m_hdcGraph, m_hPens[1]);
  344. MoveToEx(m_hdcGraph,
  345. m_rcGraph.right,
  346. GraphHeight - (g_pKernelHistory[iPane][0] * GraphHeight) / 100,
  347. (LPPOINT) NULL);
  348. for (int i = 0; i < HIST_SIZE && i * Scale < Width; i++)
  349. {
  350. LineTo(m_hdcGraph,
  351. m_rcGraph.right - Scale * i,
  352. GraphHeight - (g_pKernelHistory[iPane][i] * GraphHeight) / 100);
  353. }
  354. if (hOld)
  355. {
  356. SelectObject(m_hdcGraph, hOld);
  357. }
  358. }
  359. //
  360. // Draw a particular CPU in its pane
  361. //
  362. HGDIOBJ hOld = SelectObject(m_hdcGraph, m_hPens[0]);
  363. MoveToEx(m_hdcGraph,
  364. m_rcGraph.right,
  365. GraphHeight - (g_pCPUHistory[iPane][0] * GraphHeight) / 100,
  366. (LPPOINT) NULL);
  367. for (int i = 0; i < HIST_SIZE && i * Scale < Width; i++)
  368. {
  369. LineTo(m_hdcGraph,
  370. m_rcGraph.right - Scale * i,
  371. GraphHeight - (g_pCPUHistory[iPane][i] * GraphHeight) / 100);
  372. }
  373. if (hOld)
  374. {
  375. SelectObject(m_hdcGraph, hOld);
  376. }
  377. }
  378. else
  379. {
  380. ASSERT(iPane == 0);
  381. //
  382. // Draw the kernel times
  383. //
  384. if (g_Options.m_fKernelTimes)
  385. {
  386. HGDIOBJ hOld = SelectObject(m_hdcGraph, m_hPens[1]);
  387. DWORD dwSum = 0;
  388. for (int iCPU = 0; iCPU < g_cProcessors; iCPU++)
  389. {
  390. dwSum += g_pKernelHistory[iCPU][0];
  391. }
  392. dwSum /= g_cProcessors;
  393. MoveToEx(m_hdcGraph,
  394. m_rcGraph.right,
  395. GraphHeight - (dwSum * GraphHeight) / 100,
  396. (LPPOINT) NULL);
  397. for (int i = 0; i < HIST_SIZE && i * Scale < Width; i++)
  398. {
  399. dwSum = 0;
  400. for (iCPU = 0; iCPU < g_cProcessors; iCPU++)
  401. {
  402. dwSum += g_pKernelHistory[iCPU][i];
  403. }
  404. dwSum /= g_cProcessors;
  405. LineTo(m_hdcGraph,
  406. m_rcGraph.right - Scale * i,
  407. GraphHeight - (dwSum * GraphHeight) / 100);
  408. }
  409. if (hOld)
  410. {
  411. SelectObject(m_hdcGraph, hOld);
  412. }
  413. }
  414. //
  415. // Draw History as a sum of all CPUs
  416. //
  417. HGDIOBJ hOld = SelectObject(m_hdcGraph, m_hPens[0]);
  418. DWORD dwSum = 0;
  419. for (int iCPU = 0; iCPU < g_cProcessors; iCPU++)
  420. {
  421. dwSum += g_pCPUHistory[iCPU][0];
  422. }
  423. dwSum /= g_cProcessors;
  424. MoveToEx(m_hdcGraph,
  425. m_rcGraph.right,
  426. GraphHeight - (dwSum * GraphHeight) / 100,
  427. (LPPOINT) NULL);
  428. for (int i = 0; i < HIST_SIZE && i * Scale < Width; i++)
  429. {
  430. dwSum = 0;
  431. for (iCPU = 0; iCPU < g_cProcessors; iCPU++)
  432. {
  433. dwSum += g_pCPUHistory[iCPU][i];
  434. }
  435. dwSum /= g_cProcessors;
  436. LineTo(m_hdcGraph,
  437. m_rcGraph.right - Scale * i,
  438. GraphHeight - (dwSum * GraphHeight) / 100);
  439. }
  440. if (hOld)
  441. {
  442. SelectObject(m_hdcGraph, hOld);
  443. }
  444. }
  445. //
  446. // Memory bitmap could be wider than the target control, so find a delta
  447. //
  448. INT xDiff = (m_rcGraph.right - m_rcGraph.left) - (lpdi->rcItem.right - lpdi->rcItem.left);
  449. BitBlt( lpdi->hDC,
  450. lpdi->rcItem.left,
  451. lpdi->rcItem.top,
  452. lpdi->rcItem.right - lpdi->rcItem.left,
  453. lpdi->rcItem.bottom - lpdi->rcItem.top,
  454. m_hdcGraph,
  455. xDiff,
  456. 0,
  457. SRCCOPY);
  458. }
  459. /*++ CPerfPage::DrawMEMGraph
  460. Routine Description:
  461. Draws the Memory history graph (which is an ownerdraw control)
  462. Arguments:
  463. lpdi - LPDRAWITEMSTRUCT describing area we need to paint
  464. Return Value:
  465. Revision History:
  466. Nov-12-95 Davepl Created
  467. --*/
  468. void CPerfPage::DrawMEMGraph(LPDRAWITEMSTRUCT lpdi)
  469. {
  470. #define THISCPU 0
  471. if (NULL == m_hdcGraph)
  472. {
  473. return;
  474. }
  475. FillRect(m_hdcGraph, &m_rcGraph, (HBRUSH) GetStockObject(GRAPH_BRUSH));
  476. int Width = lpdi->rcItem.right - lpdi->rcItem.left;
  477. DrawGraphPaper(m_hdcGraph, &m_rcGraph, Width);
  478. int Scale = (Width - 1) / HIST_SIZE;
  479. if (0 == Scale)
  480. {
  481. Scale = 2;
  482. }
  483. int GraphHeight = m_rcGraph.bottom - m_rcGraph.top - 1;
  484. HGDIOBJ hOld = SelectObject(m_hdcGraph, m_hPens[MEM_PEN]);
  485. MoveToEx(m_hdcGraph,
  486. m_rcGraph.right,
  487. m_rcGraph.bottom - (g_pMEMHistory[0] * GraphHeight) / 100,
  488. (LPPOINT) NULL);
  489. for (int i = 0; i < HIST_SIZE && i * Scale < Width - 1; i++)
  490. {
  491. if (0 == g_pMEMHistory[i])
  492. {
  493. break; // End of Data
  494. }
  495. LineTo(m_hdcGraph,
  496. m_rcGraph.right - Scale * i,
  497. m_rcGraph.bottom - (g_pMEMHistory[i] * GraphHeight) / 100);
  498. }
  499. BitBlt( lpdi->hDC,
  500. lpdi->rcItem.left,
  501. lpdi->rcItem.top,
  502. lpdi->rcItem.right - lpdi->rcItem.left,
  503. lpdi->rcItem.bottom - lpdi->rcItem.top,
  504. m_hdcGraph,
  505. 0,
  506. 0,
  507. SRCCOPY);
  508. if (hOld)
  509. {
  510. SelectObject(m_hdcGraph, hOld);
  511. }
  512. }
  513. /*++ CPerfPage::UpdateGraphs
  514. Routine Description:
  515. Adds and removed CPU panes as required
  516. Arguments:
  517. none
  518. Return Value:
  519. none
  520. Revision History:
  521. Dec-16-96 Davepl Create
  522. ***/
  523. void CPerfPage::UpdateGraphs()
  524. {
  525. UINT i;
  526. for ( i = 0; i < g_cProcessors; i ++ )
  527. {
  528. //
  529. // Make sure we have enough windows to show all the processors
  530. //
  531. HWND hwnd = GetDlgItem( m_hPage, IDC_CPUGRAPH + i );
  532. if ( NULL == hwnd )
  533. {
  534. hwnd = CreateWindowEx( WS_EX_CLIENTEDGE
  535. , L"BUTTON"
  536. , L""
  537. , BS_OWNERDRAW | WS_DISABLED | WS_CHILD
  538. , 0
  539. , 0
  540. , 1
  541. , 1
  542. , m_hPage
  543. , (HMENU) ((ULONGLONG)IDC_CPUGRAPH + i)
  544. , NULL // ignored
  545. , NULL
  546. );
  547. }
  548. if ( NULL != hwnd && 0 != i )
  549. {
  550. // Show/hide the window depending on the mode
  551. ShowWindow( hwnd, CM_PANES == g_Options.m_cmHistMode ? SW_SHOW : SW_HIDE );
  552. }
  553. }
  554. //
  555. // Hide/show everything but the CPU meters when we're in notitle/title mode
  556. //
  557. for (i = 0; i < ARRAYSIZE(aPerfControls); i++)
  558. {
  559. ShowWindow(GetDlgItem(m_hPage, aPerfControls[i]), g_Options.m_fNoTitle ? SW_HIDE : SW_SHOW);
  560. }
  561. ShowWindow(GetDlgItem(m_hPage, IDC_MEMGRAPH), g_Options.m_fNoTitle ? SW_HIDE : SW_SHOW);
  562. ShowWindow(GetDlgItem(m_hPage, IDC_MEMFRAME), g_Options.m_fNoTitle ? SW_HIDE : SW_SHOW);
  563. ShowWindow(GetDlgItem(m_hPage, IDC_MEMBARFRAME), g_Options.m_fNoTitle ? SW_HIDE : SW_SHOW);
  564. ShowWindow(GetDlgItem(m_hPage, IDC_MEMMETER), g_Options.m_fNoTitle ? SW_HIDE : SW_SHOW);
  565. SizePerfPage();
  566. }
  567. /*++ CPerfPage::DrawCPUDigits
  568. Routine Description:
  569. Draws the CPU meter and digits
  570. Arguments:
  571. lpdi - LPDRAWITEMSTRUCT describing area we need to paint
  572. Return Value:
  573. Revision History:
  574. Nov-12-95 Davepl Created
  575. --*/
  576. int GetCurFontSize(HDC hdc)
  577. {
  578. int iRet = 0;
  579. LOGFONT lf;
  580. HFONT hf = (HFONT) GetCurrentObject(hdc, OBJ_FONT);
  581. if (hf)
  582. {
  583. if (GetObject(hf, sizeof(LOGFONT), &lf))
  584. {
  585. iRet = lf.lfHeight;
  586. if (iRet < 0)
  587. {
  588. iRet = (-iRet);
  589. }
  590. }
  591. }
  592. return iRet;
  593. }
  594. //
  595. //
  596. //
  597. void CPerfPage::DrawCPUDigits(LPDRAWITEMSTRUCT lpdi)
  598. {
  599. HBRUSH hBlack = (HBRUSH) GetStockObject(BLACK_BRUSH);
  600. HGDIOBJ hOld = SelectObject(lpdi->hDC, hBlack);
  601. Rectangle(lpdi->hDC, lpdi->rcItem.left, lpdi->rcItem.top, lpdi->rcItem.right, lpdi->rcItem.bottom);
  602. //
  603. // Draw the digits into the ownder draw control
  604. //
  605. INT xBarOffset = ((lpdi->rcItem.right - lpdi->rcItem.left) - STRIP_WIDTH) / 2;
  606. RECT rcBar;
  607. GetWindowRect(GetDlgItem(m_hPage, IDC_MEMMETER), &rcBar);
  608. INT cBarHeight = lpdi->rcItem.bottom - lpdi->rcItem.top - (GetCurFontSize(lpdi->hDC) + g_DefSpacing * 3);
  609. if (cBarHeight <= 0)
  610. {
  611. return;
  612. }
  613. INT ctmpBarLitPixels = (g_CPUUsage * cBarHeight) / 100;
  614. INT ctmpBarRedPixels = g_Options.m_fKernelTimes ? ctmpBarRedPixels = (g_KernelUsage * cBarHeight) / 100 : 0;
  615. INT cBarUnLitPixels = cBarHeight - ctmpBarLitPixels;
  616. cBarUnLitPixels = (cBarUnLitPixels / 3) * 3;
  617. INT cBarLitPixels = cBarHeight - cBarUnLitPixels;
  618. INT cBarRedPixels = ctmpBarRedPixels;
  619. SetBkMode(lpdi->hDC, TRANSPARENT);
  620. SetTextColor(lpdi->hDC, GRAPH_TEXT_COLOR);
  621. WCHAR szBuf[8];
  622. StringCchPrintf( szBuf, ARRAYSIZE(szBuf), L"%d %%", g_CPUUsage); // don't care if it truncates - UI only
  623. RECT rcOut = lpdi->rcItem;
  624. rcOut.bottom -= 4;
  625. DrawText(lpdi->hDC, szBuf, -1, &rcOut, DT_SINGLELINE | DT_CENTER | DT_BOTTOM);
  626. HDC hdcMem = CreateCompatibleDC(lpdi->hDC);
  627. if (hdcMem)
  628. {
  629. //
  630. // Draw the CPU meter
  631. //
  632. //
  633. // Draw unlit portion
  634. //
  635. if (cBarHeight != cBarLitPixels)
  636. {
  637. INT cUnlit = cBarHeight - cBarLitPixels;
  638. INT cOffset = 0;
  639. HGDIOBJ hOldObj = SelectObject(hdcMem, m_hStripUnlit);
  640. while (cUnlit > 0)
  641. {
  642. BitBlt(lpdi->hDC, xBarOffset, g_DefSpacing + cOffset,
  643. STRIP_WIDTH, min(cUnlit, STRIP_HEIGHT),
  644. hdcMem,
  645. 0, 0, SRCCOPY);
  646. cOffset += min(cUnlit, STRIP_HEIGHT);
  647. cUnlit -= min(cUnlit, STRIP_HEIGHT);
  648. }
  649. if ( NULL != hOldObj )
  650. {
  651. SelectObject( hdcMem, hOldObj );
  652. }
  653. }
  654. //
  655. // Draw lit portion
  656. //
  657. if (0 != cBarLitPixels)
  658. {
  659. HGDIOBJ hOldObj = SelectObject(hdcMem, m_hStripLit);
  660. INT cOffset = 0;
  661. INT cLit = cBarLitPixels - cBarRedPixels;
  662. while (cLit > 0)
  663. {
  664. BitBlt(lpdi->hDC, xBarOffset, g_DefSpacing + (cBarHeight - cBarLitPixels) + cOffset,
  665. STRIP_WIDTH, min(STRIP_HEIGHT, cLit),
  666. hdcMem,
  667. 0, 0, SRCCOPY);
  668. cOffset += min(cLit, STRIP_HEIGHT);
  669. cLit -= min(cLit, STRIP_HEIGHT);
  670. }
  671. if ( NULL != hOldObj )
  672. {
  673. SelectObject( hdcMem, hOldObj );
  674. }
  675. }
  676. if (0 != cBarRedPixels)
  677. {
  678. HGDIOBJ hOldObj = SelectObject(hdcMem, m_hStripLitRed);
  679. INT cOffset = 0;
  680. INT cRed = cBarRedPixels;
  681. while (cRed > 0)
  682. {
  683. BitBlt(lpdi->hDC, xBarOffset, g_DefSpacing + (cBarHeight - cBarRedPixels) + cOffset,
  684. STRIP_WIDTH, min(cRed, STRIP_HEIGHT),
  685. hdcMem,
  686. 0, 0, SRCCOPY);
  687. cOffset += min(cRed, STRIP_HEIGHT);
  688. cRed -= min(cRed, STRIP_HEIGHT);
  689. }
  690. if ( NULL != hOldObj )
  691. {
  692. SelectObject( hdcMem, hOldObj );
  693. }
  694. }
  695. DeleteDC(hdcMem);
  696. }
  697. SelectObject(lpdi->hDC, hOld);
  698. }
  699. // CPerfPage::DrawMEMMeter
  700. //
  701. // Draws the memory meter
  702. void CPerfPage::DrawMEMMeter(LPDRAWITEMSTRUCT lpdi)
  703. {
  704. HBRUSH hBlack = (HBRUSH) GetStockObject(BLACK_BRUSH);
  705. HGDIOBJ hOld = SelectObject(lpdi->hDC, hBlack);
  706. Rectangle(lpdi->hDC, lpdi->rcItem.left, lpdi->rcItem.top, lpdi->rcItem.right, lpdi->rcItem.bottom);
  707. INT xBarOffset = ((lpdi->rcItem.right - lpdi->rcItem.left) - STRIP_WIDTH) / 2;
  708. SetBkMode(lpdi->hDC, TRANSPARENT);
  709. SetTextColor(lpdi->hDC, GRAPH_TEXT_COLOR);
  710. WCHAR szBuf[32];
  711. StrFormatByteSize64( g_MEMUsage * 1024, szBuf, ARRAYSIZE(szBuf) );
  712. RECT rcOut = lpdi->rcItem;
  713. rcOut.bottom -= 4;
  714. DrawText(lpdi->hDC, szBuf, -1, &rcOut, DT_SINGLELINE | DT_CENTER | DT_BOTTOM);
  715. HDC hdcMem = CreateCompatibleDC(lpdi->hDC);
  716. if (hdcMem)
  717. {
  718. //
  719. // Draw the CPU meter
  720. //
  721. //
  722. // Draw unlit portion
  723. //
  724. INT cBarHeight = lpdi->rcItem.bottom - lpdi->rcItem.top - (GetCurFontSize(lpdi->hDC) + g_DefSpacing * 3);
  725. if (cBarHeight > 0)
  726. {
  727. INT cBarLitPixels = (INT)(( g_MEMUsage * cBarHeight ) / g_MEMMax);
  728. cBarLitPixels = (cBarLitPixels / 3) * 3;
  729. if (cBarHeight != cBarLitPixels)
  730. {
  731. HGDIOBJ hOldObj = SelectObject(hdcMem, m_hStripUnlit);
  732. INT cUnlit = cBarHeight - cBarLitPixels;
  733. INT cOffset = 0;
  734. while (cUnlit > 0)
  735. {
  736. BitBlt(lpdi->hDC, xBarOffset, g_DefSpacing + cOffset,
  737. STRIP_WIDTH, min(cUnlit, STRIP_HEIGHT),
  738. hdcMem,
  739. 0, 0, SRCCOPY);
  740. cOffset += min(cUnlit, STRIP_HEIGHT);
  741. cUnlit -= min(cUnlit, STRIP_HEIGHT);
  742. }
  743. if ( NULL != hOldObj )
  744. {
  745. SelectObject( hdcMem, hOldObj );
  746. }
  747. }
  748. //
  749. // Draw lit portion
  750. //
  751. if (0 != cBarLitPixels)
  752. {
  753. HGDIOBJ hOldObj = SelectObject(hdcMem, m_hStripLit);
  754. INT cOffset = 0;
  755. INT cLit = cBarLitPixels;
  756. while (cLit > 0)
  757. {
  758. BitBlt(lpdi->hDC, xBarOffset, g_DefSpacing + (cBarHeight - cBarLitPixels) + cOffset,
  759. STRIP_WIDTH, min(STRIP_HEIGHT, cLit),
  760. hdcMem,
  761. 0, 0, SRCCOPY);
  762. cOffset += min(cLit, STRIP_HEIGHT);
  763. cLit -= min(cLit, STRIP_HEIGHT);
  764. }
  765. if ( NULL != hOldObj )
  766. {
  767. SelectObject( hdcMem, hOldObj );
  768. }
  769. }
  770. }
  771. DeleteDC(hdcMem);
  772. }
  773. SelectObject(lpdi->hDC, hOld);
  774. }
  775. /*++ CPerfPage::TimerEvent
  776. Routine Description:
  777. Called by main app when the update time fires
  778. Arguments:
  779. Return Value:
  780. Revision History:
  781. Nov-12-95 Davepl Created
  782. --*/
  783. void CPerfPage::TimerEvent()
  784. {
  785. CalcCpuTime(TRUE);
  786. g_Scrollamount+=2;
  787. g_Scrollamount %= GRAPHPAPERSIZE;
  788. //
  789. // Force the displays to update
  790. //
  791. if (FALSE == IsIconic(g_hMainWnd))
  792. {
  793. InvalidateRect(GetDlgItem(m_hPage, IDC_CPUMETER), NULL, FALSE);
  794. UpdateWindow(GetDlgItem(m_hPage, IDC_CPUMETER));
  795. InvalidateRect(GetDlgItem(m_hPage, IDC_MEMMETER), NULL, FALSE);
  796. UpdateWindow(GetDlgItem(m_hPage, IDC_MEMMETER));
  797. UINT cPanes = ( CM_PANES == g_Options.m_cmHistMode ? g_cProcessors : 1);
  798. for (UINT i = 0; i < cPanes; i ++)
  799. {
  800. HWND hwnd = GetDlgItem(m_hPage, IDC_CPUGRAPH + i);
  801. if ( NULL != hwnd )
  802. {
  803. InvalidateRect(hwnd, NULL, FALSE);
  804. UpdateWindow(hwnd);
  805. }
  806. }
  807. InvalidateRect(GetDlgItem(m_hPage, IDC_MEMGRAPH), NULL, FALSE);
  808. UpdateWindow(GetDlgItem(m_hPage, IDC_MEMGRAPH));
  809. }
  810. }
  811. /*++ PerfPageProc
  812. Routine Description:
  813. Dialogproc for the performance page.
  814. Arguments:
  815. hwnd - handle to dialog box
  816. uMsg - message
  817. wParam - first message parameter
  818. lParam - second message parameter
  819. Return Value:
  820. For WM_INITDIALOG, TRUE == user32 sets focus, FALSE == we set focus
  821. For others, TRUE == this proc handles the message
  822. Revision History:
  823. Nov-12-95 Davepl Created
  824. --*/
  825. INT_PTR CALLBACK PerfPageProc(
  826. HWND hwnd, // handle to dialog box
  827. UINT uMsg, // message
  828. WPARAM wParam, // first message parameter
  829. LPARAM lParam // second message parameter
  830. )
  831. {
  832. CPerfPage * thispage = (CPerfPage *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  833. //
  834. // See if the parent wants this message
  835. //
  836. if (TRUE == CheckParentDeferrals(uMsg, wParam, lParam))
  837. {
  838. return TRUE;
  839. }
  840. switch(uMsg)
  841. {
  842. case WM_INITDIALOG:
  843. {
  844. SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
  845. DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
  846. dwStyle |= WS_CLIPCHILDREN;
  847. SetWindowLong(hwnd, GWL_STYLE, dwStyle);
  848. if (IS_WINDOW_RTL_MIRRORED(hwnd))
  849. {
  850. HWND hItem;
  851. LONG lExtStyle;
  852. hItem = GetDlgItem(hwnd,IDC_CPUMETER);
  853. lExtStyle = GetWindowLong(hItem,GWL_EXSTYLE);
  854. SetWindowLong(hItem,GWL_EXSTYLE, lExtStyle & ~(RTL_MIRRORED_WINDOW | RTL_NOINHERITLAYOUT));
  855. hItem = GetDlgItem(hwnd,IDC_MEMMETER);
  856. lExtStyle = GetWindowLong(hItem,GWL_EXSTYLE);
  857. SetWindowLong(hItem,GWL_EXSTYLE, lExtStyle & ~(dwExStyleRTLMirrorWnd | dwExStyleNoInheritLayout));
  858. }
  859. }
  860. // We handle focus during Activate(). Return FALSE here so the
  861. // dialog manager doesn't try to set focus.
  862. return FALSE;
  863. case WM_LBUTTONUP:
  864. case WM_LBUTTONDOWN:
  865. //
  866. // We need to fake client mouse clicks in this child to appear as nonclient
  867. // (caption) clicks in the parent so that the user can drag the entire app
  868. // when the title bar is hidden by dragging the client area of this child
  869. //
  870. if (g_Options.m_fNoTitle)
  871. {
  872. SendMessage(g_hMainWnd,
  873. uMsg == WM_LBUTTONUP ? WM_NCLBUTTONUP : WM_NCLBUTTONDOWN,
  874. HTCAPTION,
  875. lParam);
  876. }
  877. break;
  878. case WM_NCLBUTTONDBLCLK:
  879. case WM_LBUTTONDBLCLK:
  880. SendMessage(g_hMainWnd, uMsg, wParam, lParam);
  881. break;
  882. case WM_CTLCOLORBTN:
  883. {
  884. const static int rgGraphs[] =
  885. {
  886. IDC_MEMGRAPH,
  887. IDC_MEMMETER,
  888. IDC_CPUMETER
  889. };
  890. int uCtlId = GetDlgCtrlID((HWND)lParam);
  891. for (int i = 0; i < ARRAYSIZE(rgGraphs); i++)
  892. {
  893. if ( uCtlId == rgGraphs[i] )
  894. {
  895. return (INT_PTR) GetStockObject(GRAPH_BRUSH);
  896. }
  897. }
  898. // All CPU graphs should use the GRAPH_BRUSH
  899. if ( uCtlId >= IDC_CPUGRAPH && uCtlId <= IDC_CPUGRAPH + g_cProcessors )
  900. {
  901. return (INT_PTR) GetStockObject(GRAPH_BRUSH);
  902. }
  903. }
  904. break;
  905. case WM_SIZE:
  906. //
  907. // Size our kids
  908. //
  909. thispage->SizePerfPage();
  910. return FALSE;
  911. case WM_DRAWITEM:
  912. //
  913. // Draw one of our owner draw controls
  914. //
  915. if (wParam >= IDC_CPUGRAPH && wParam <= (WPARAM)(IDC_CPUGRAPH + g_cProcessors) )
  916. {
  917. thispage->DrawCPUGraph( (LPDRAWITEMSTRUCT) lParam, (UINT)wParam - IDC_CPUGRAPH);
  918. return TRUE;
  919. }
  920. else if (IDC_CPUMETER == wParam)
  921. {
  922. thispage->DrawCPUDigits( (LPDRAWITEMSTRUCT) lParam);
  923. return TRUE;
  924. }
  925. else if (IDC_MEMMETER == wParam)
  926. {
  927. thispage->DrawMEMMeter( (LPDRAWITEMSTRUCT) lParam);
  928. return TRUE;
  929. }
  930. else if (IDC_MEMGRAPH == wParam)
  931. {
  932. thispage->DrawMEMGraph( (LPDRAWITEMSTRUCT) lParam);
  933. return TRUE;
  934. }
  935. break;
  936. }
  937. return FALSE;
  938. }
  939. /*++ CPerfPage::GetTitle
  940. Routine Description:
  941. Copies the title of this page to the caller-supplied buffer
  942. Arguments:
  943. pszText - the buffer to copy to
  944. bufsize - size of buffer, in characters
  945. Return Value:
  946. Revision History:
  947. Nov-12-95 Davepl Created
  948. --*/
  949. void CPerfPage::GetTitle(LPTSTR pszText, size_t bufsize)
  950. {
  951. LoadString(g_hInstance, IDS_PERFPAGETITLE, pszText, static_cast<int>(bufsize));
  952. }
  953. /*++ CPerfPage::Activate
  954. Routine Description:
  955. Brings this page to the front, sets its initial position,
  956. and shows it
  957. Arguments:
  958. Return Value:
  959. HRESULT (S_OK on success)
  960. Revision History:
  961. Nov-12-95 Davepl Created
  962. --*/
  963. HRESULT CPerfPage::Activate()
  964. {
  965. // Adjust the size and position of our dialog relative
  966. // to the tab control which "owns" us
  967. RECT rcParent;
  968. GetClientRect(m_hwndTabs, &rcParent);
  969. MapWindowPoints(m_hwndTabs, g_hMainWnd, (LPPOINT) &rcParent, 2);
  970. TabCtrl_AdjustRect(m_hwndTabs, FALSE, &rcParent);
  971. SetWindowPos(m_hPage,
  972. HWND_TOP,
  973. rcParent.left, rcParent.top,
  974. rcParent.right - rcParent.left, rcParent.bottom - rcParent.top,
  975. 0);
  976. //
  977. // Make this page visible
  978. //
  979. ShowWindow(m_hPage, SW_SHOW);
  980. //
  981. // Make the CPU graphs visible or invisible depending on its current mode
  982. //
  983. UpdateGraphs();
  984. //
  985. // Change the menu bar to be the menu for this page
  986. //
  987. HMENU hMenuOld = GetMenu(g_hMainWnd);
  988. HMENU hMenuNew = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_MAINMENU_PERF));
  989. AdjustMenuBar(hMenuNew);
  990. if (hMenuNew && SHRestricted(REST_NORUN))
  991. {
  992. DeleteMenu(hMenuNew, IDM_RUN, MF_BYCOMMAND);
  993. }
  994. g_hMenu = hMenuNew;
  995. if (g_Options.m_fNoTitle == FALSE)
  996. {
  997. SetMenu(g_hMainWnd, hMenuNew);
  998. }
  999. if (hMenuOld)
  1000. {
  1001. DestroyMenu(hMenuOld);
  1002. }
  1003. // There are no tabstops on this page, but we have to set focus somewhere.
  1004. // If we don't, it may stay on the previous page, now hidden, which can
  1005. // confuse the dialog manager and may cause us to hang.
  1006. SetFocus(m_hwndTabs);
  1007. return S_OK;
  1008. }
  1009. /*++ CPerfPage::Initialize
  1010. Routine Description:
  1011. Loads the resources we need for this page, creates the inmemory DCs
  1012. and bitmaps for the charts, and creates the actual window (a dialog)
  1013. that represents this page
  1014. Arguments:
  1015. hwndParent - Parent on which to base sizing on: not used for creation,
  1016. since the main app window is always used as the parent in
  1017. order to keep tab order correct
  1018. Return Value:
  1019. Revision History:
  1020. Nov-12-95 Davepl Created
  1021. --*/
  1022. HRESULT CPerfPage::Initialize(HWND hwndParent)
  1023. {
  1024. // Our pseudo-parent is the tab contrl, and is what we base our
  1025. // sizing on. However, in order to keep tab order right among
  1026. // the controls, we actually create ourselves with the main
  1027. // window as the parent
  1028. m_hwndTabs = hwndParent;
  1029. //
  1030. // Create the color pens
  1031. //
  1032. CreatePens();
  1033. m_hStripLit = (HBITMAP) LoadImage(g_hInstance, MAKEINTRESOURCE(LED_STRIP_LIT),
  1034. IMAGE_BITMAP,
  1035. 0, 0,
  1036. LR_DEFAULTCOLOR);
  1037. m_hStripLitRed = (HBITMAP) LoadImage(g_hInstance, MAKEINTRESOURCE(LED_STRIP_LIT_RED),
  1038. IMAGE_BITMAP,
  1039. 0, 0,
  1040. LR_DEFAULTCOLOR);
  1041. m_hStripUnlit = (HBITMAP) LoadImage(g_hInstance, MAKEINTRESOURCE(LED_STRIP_UNLIT),
  1042. IMAGE_BITMAP,
  1043. 0, 0,
  1044. LR_DEFAULTCOLOR);
  1045. //
  1046. // Create the dialog which represents the body of this page
  1047. //
  1048. m_hPage = CreateDialogParam(
  1049. g_hInstance, // handle to application instance
  1050. MAKEINTRESOURCE(IDD_PERFPAGE), // identifies dialog box template name
  1051. g_hMainWnd, // handle to owner window
  1052. PerfPageProc, // pointer to dialog box procedure
  1053. (LPARAM) this ); // User data (our this pointer)
  1054. if (NULL == m_hPage)
  1055. {
  1056. return GetLastHRESULT();
  1057. }
  1058. return S_OK;
  1059. }
  1060. /*++ CPerfPage::CreateMemoryBitmaps
  1061. Routine Description:
  1062. Creates the inmemory bitmaps used to draw the history graphics
  1063. Arguments:
  1064. x, y - size of bitmap to create
  1065. Return Value:
  1066. Revision History:
  1067. Nov-12-95 Davepl Created
  1068. --*/
  1069. HRESULT CPerfPage::CreateMemoryBitmaps(int x, int y)
  1070. {
  1071. //
  1072. // Create the inmemory bitmaps and DCs that we will use
  1073. //
  1074. HDC hdcPage = GetDC(m_hPage);
  1075. m_hdcGraph = CreateCompatibleDC(hdcPage);
  1076. if (NULL == m_hdcGraph)
  1077. {
  1078. ReleaseDC(m_hPage, hdcPage);
  1079. return GetLastHRESULT();
  1080. }
  1081. m_rcGraph.left = 0;
  1082. m_rcGraph.top = 0;
  1083. m_rcGraph.right = x;
  1084. m_rcGraph.bottom = y;
  1085. m_hbmpGraph = CreateCompatibleBitmap(hdcPage, x, y);
  1086. ReleaseDC(m_hPage, hdcPage);
  1087. if (NULL == m_hbmpGraph)
  1088. {
  1089. HRESULT hr = GetLastHRESULT();
  1090. DeleteDC(m_hdcGraph);
  1091. m_hdcGraph = NULL;
  1092. return hr;
  1093. }
  1094. // Select the bitmap into the DC
  1095. m_hObjOld = SelectObject(m_hdcGraph, m_hbmpGraph);
  1096. return S_OK;
  1097. }
  1098. /*++ CPerfPage::FreeMemoryBitmaps
  1099. Routine Description:
  1100. Frees the inmemory bitmaps used to drag the history graphs
  1101. Arguments:
  1102. Return Value:
  1103. Revision History:
  1104. Nov-12-95 Davepl Created
  1105. --*/
  1106. void CPerfPage::FreeMemoryBitmaps()
  1107. {
  1108. if (m_hdcGraph)
  1109. {
  1110. if (m_hObjOld)
  1111. {
  1112. SelectObject(m_hdcGraph, m_hObjOld);
  1113. }
  1114. DeleteDC(m_hdcGraph);
  1115. }
  1116. if (m_hbmpGraph)
  1117. {
  1118. DeleteObject(m_hbmpGraph);
  1119. }
  1120. }
  1121. /*++ CPerfPage::Deactivate
  1122. Routine Description:
  1123. Called when this page is losing its place up front
  1124. Arguments:
  1125. Return Value:
  1126. Revision History:
  1127. Nov-16-95 Davepl Created
  1128. --*/
  1129. void CPerfPage::Deactivate()
  1130. {
  1131. if (m_hPage)
  1132. {
  1133. ShowWindow(m_hPage, SW_HIDE);
  1134. }
  1135. }
  1136. /*++ CPerfPage::Destroy
  1137. Routine Description:
  1138. Frees whatever has been allocated by the Initialize call
  1139. Arguments:
  1140. Return Value:
  1141. Revision History:
  1142. Nov-12-95 Davepl Created
  1143. --*/
  1144. HRESULT CPerfPage::Destroy()
  1145. {
  1146. //
  1147. // When we are being destroyed, kill off our dialog
  1148. //
  1149. ReleasePens();
  1150. if (m_hPage)
  1151. {
  1152. DestroyWindow(m_hPage);
  1153. m_hPage = NULL;
  1154. }
  1155. if (m_hStripLit)
  1156. {
  1157. DeleteObject(m_hStripLit);
  1158. m_hStripLit = NULL;
  1159. }
  1160. if (m_hStripUnlit)
  1161. {
  1162. DeleteObject(m_hStripUnlit);
  1163. m_hStripUnlit = NULL;
  1164. }
  1165. if (m_hStripLitRed)
  1166. {
  1167. DeleteObject(m_hStripLitRed);
  1168. m_hStripLitRed = NULL;
  1169. }
  1170. FreeMemoryBitmaps( );
  1171. return S_OK;
  1172. }
  1173. /*++
  1174. Routine Description:
  1175. Initialize data for perf measurements
  1176. Arguments:
  1177. None
  1178. Return Value:
  1179. Number of system processors (0 if error)
  1180. Revision History:
  1181. 10-13-95 Modified from WPERF
  1182. --*/
  1183. BYTE InitPerfInfo()
  1184. {
  1185. SYSTEM_BASIC_INFORMATION BasicInfo;
  1186. PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PPerfInfo;
  1187. SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ProcessorInfo[MAXIMUM_PROCESSORS];
  1188. int i;
  1189. NTSTATUS Status = NtQuerySystemInformation(
  1190. SystemBasicInformation,
  1191. &BasicInfo,
  1192. sizeof(BasicInfo),
  1193. NULL
  1194. );
  1195. if (!NT_SUCCESS(Status))
  1196. {
  1197. return 0;
  1198. }
  1199. g_PageSize = BasicInfo.PageSize;
  1200. g_cProcessors = BasicInfo.NumberOfProcessors;
  1201. if (g_cProcessors > MAXIMUM_PROCESSORS) {
  1202. g_cProcessors = MAXIMUM_PROCESSORS;
  1203. }
  1204. for (i = 0; i < g_cProcessors; i++)
  1205. {
  1206. g_pCPUHistory[i] = (LPBYTE) LocalAlloc(LPTR, HIST_SIZE * sizeof(LPBYTE));
  1207. if (NULL == g_pCPUHistory[i])
  1208. {
  1209. return 0;
  1210. }
  1211. g_pKernelHistory[i] = (LPBYTE) LocalAlloc(LPTR, HIST_SIZE * sizeof(LPBYTE));
  1212. if (NULL == g_pKernelHistory[i])
  1213. {
  1214. return 0;
  1215. }
  1216. }
  1217. g_pMEMHistory = (LPBYTE) LocalAlloc(LPTR, HIST_SIZE * sizeof(LPBYTE));
  1218. if (NULL == g_pMEMHistory)
  1219. {
  1220. return 0;
  1221. }
  1222. Status = NtQuerySystemInformation(
  1223. SystemProcessorPerformanceInformation,
  1224. ProcessorInfo,
  1225. sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * MAXIMUM_PROCESSORS,
  1226. NULL
  1227. );
  1228. if (!NT_SUCCESS(Status))
  1229. {
  1230. return 0;
  1231. }
  1232. PPerfInfo = ProcessorInfo;
  1233. for (i=0; i < g_cProcessors; i++)
  1234. {
  1235. PreviousCPUIdleTime[i] = PPerfInfo->IdleTime;
  1236. PreviousCPUTotalTime[i].QuadPart = PPerfInfo->UserTime.QuadPart +
  1237. PPerfInfo->KernelTime.QuadPart;
  1238. PreviousCPUKernelTime[i].QuadPart = PPerfInfo->KernelTime.QuadPart +
  1239. PPerfInfo->IdleTime.QuadPart;
  1240. // PPerfInfo->IdleTime.QuadPart;
  1241. PPerfInfo++;
  1242. }
  1243. //
  1244. // Get the maximum commit limit
  1245. //
  1246. SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
  1247. Status = NtQuerySystemInformation(
  1248. SystemPerformanceInformation,
  1249. &PerfInfo,
  1250. sizeof(PerfInfo),
  1251. NULL);
  1252. if (!NT_SUCCESS(Status))
  1253. {
  1254. return 0;
  1255. }
  1256. g_MEMMax = PerfInfo.CommitLimit * ( g_PageSize / 1024 );
  1257. return(g_cProcessors);
  1258. }
  1259. /*++ ReleasePerfInfo
  1260. Routine Description:
  1261. Frees the history buffers
  1262. Arguments:
  1263. Return Value:
  1264. Revision History:
  1265. Nov-13-95 DavePl Created
  1266. --*/
  1267. void ReleasePerfInfo()
  1268. {
  1269. for (int i = 0; i < g_cProcessors; i++)
  1270. {
  1271. if (g_pCPUHistory[i])
  1272. {
  1273. LocalFree(g_pCPUHistory[i]);
  1274. g_pCPUHistory[i] = NULL;
  1275. }
  1276. if (g_pKernelHistory[i])
  1277. {
  1278. LocalFree(g_pKernelHistory[i]);
  1279. g_pKernelHistory[i] = NULL;
  1280. }
  1281. }
  1282. if (g_pMEMHistory)
  1283. {
  1284. LocalFree(g_pMEMHistory);
  1285. }
  1286. }
  1287. /*++ CalcCpuTime
  1288. Routine Description:
  1289. calculate and return %cpu time and time periods
  1290. Arguments:
  1291. None
  1292. Notes:
  1293. Revision History:
  1294. Nov-13-95 DavePl Created
  1295. --*/
  1296. void CalcCpuTime(BOOL fUpdateHistory)
  1297. {
  1298. SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ProcessorInfo[MAXIMUM_PROCESSORS];
  1299. LARGE_INTEGER CPUIdleTime[MAXIMUM_PROCESSORS];
  1300. LARGE_INTEGER CPUTotalTime[MAXIMUM_PROCESSORS];
  1301. LARGE_INTEGER CPUKernelTime[MAXIMUM_PROCESSORS];
  1302. LARGE_INTEGER SumIdleTime = { 0 ,0 };
  1303. LARGE_INTEGER SumTotalTime = { 0, 0 };
  1304. LARGE_INTEGER SumKernelTime = { 0, 0 };
  1305. NTSTATUS Status;
  1306. Status = NtQuerySystemInformation(
  1307. SystemProcessorPerformanceInformation,
  1308. ProcessorInfo,
  1309. sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * MAXIMUM_PROCESSORS,
  1310. NULL
  1311. );
  1312. if (!NT_SUCCESS(Status))
  1313. {
  1314. return;
  1315. }
  1316. //
  1317. // Walk through the info for each CPU, and compile
  1318. //
  1319. // - Amount of time each CPU has spent idle (since last check)
  1320. // - Amount of time each CPU has spent entirely (since last check)
  1321. //
  1322. // In addition to keeping per-CPU stats, compile a sum for
  1323. //
  1324. // - Amount of time system has spent idle (since last check)
  1325. // - Amount of time that has elapsed, in total (since last check)
  1326. //
  1327. for (int ListIndex = 0; ListIndex < g_cProcessors; ListIndex++)
  1328. {
  1329. LARGE_INTEGER DeltaCPUIdleTime;
  1330. LARGE_INTEGER DeltaCPUTotalTime;
  1331. LARGE_INTEGER DeltaCPUKernelTime;
  1332. CPUIdleTime[ListIndex].QuadPart = ProcessorInfo[ListIndex].IdleTime.QuadPart;
  1333. CPUKernelTime[ListIndex].QuadPart= ProcessorInfo[ListIndex].KernelTime.QuadPart-
  1334. ProcessorInfo[ListIndex].IdleTime.QuadPart;
  1335. CPUTotalTime[ListIndex].QuadPart = ProcessorInfo[ListIndex].KernelTime.QuadPart +
  1336. ProcessorInfo[ListIndex].UserTime.QuadPart;// +
  1337. //ProcessorInfo[ListIndex].IdleTime.QuadPart;
  1338. DeltaCPUIdleTime.QuadPart = CPUIdleTime[ListIndex].QuadPart -
  1339. PreviousCPUIdleTime[ListIndex].QuadPart;
  1340. DeltaCPUKernelTime.QuadPart = CPUKernelTime[ListIndex].QuadPart -
  1341. PreviousCPUKernelTime[ListIndex].QuadPart;
  1342. DeltaCPUTotalTime.QuadPart = CPUTotalTime[ListIndex].QuadPart -
  1343. PreviousCPUTotalTime[ListIndex].QuadPart;
  1344. SumIdleTime.QuadPart += DeltaCPUIdleTime.QuadPart;
  1345. SumTotalTime.QuadPart += DeltaCPUTotalTime.QuadPart;
  1346. SumKernelTime.QuadPart += DeltaCPUKernelTime.QuadPart;
  1347. // Calc CPU Usage % for this processor, scroll the history buffer, and store
  1348. // the newly calced value at the head of the history buffer
  1349. BYTE ThisCPU;
  1350. if (DeltaCPUTotalTime.QuadPart != 0)
  1351. {
  1352. ThisCPU = static_cast<BYTE>(100 - ((DeltaCPUIdleTime.QuadPart * 100) / DeltaCPUTotalTime.QuadPart));
  1353. }
  1354. else
  1355. {
  1356. ThisCPU = 0;
  1357. }
  1358. BYTE * pbHistory = g_pCPUHistory[ListIndex];
  1359. MoveMemory((LPVOID) (pbHistory + 1),
  1360. (LPVOID) (pbHistory),
  1361. sizeof(BYTE) * (HIST_SIZE - 1) );
  1362. pbHistory[0] = ThisCPU;
  1363. BYTE ThisKernel;
  1364. if (DeltaCPUTotalTime.QuadPart != 0)
  1365. {
  1366. ThisKernel = static_cast<BYTE>(((DeltaCPUKernelTime.QuadPart * 100) / DeltaCPUTotalTime.QuadPart));
  1367. }
  1368. else
  1369. {
  1370. ThisKernel = 0;
  1371. }
  1372. pbHistory = g_pKernelHistory[ListIndex];
  1373. MoveMemory((LPVOID) (pbHistory + 1),
  1374. (LPVOID) (pbHistory),
  1375. sizeof(BYTE) * (HIST_SIZE - 1) );
  1376. pbHistory[0] = ThisKernel;
  1377. PreviousCPUTotalTime[ListIndex].QuadPart = CPUTotalTime[ListIndex].QuadPart;
  1378. PreviousCPUIdleTime[ListIndex].QuadPart = CPUIdleTime[ListIndex].QuadPart;
  1379. PreviousCPUKernelTime[ListIndex].QuadPart = CPUKernelTime[ListIndex].QuadPart;
  1380. }
  1381. if (SumTotalTime.QuadPart != 0)
  1382. {
  1383. g_CPUUsage = (BYTE) (100 - ((SumIdleTime.QuadPart * 100) / SumTotalTime.QuadPart));
  1384. }
  1385. else
  1386. {
  1387. g_CPUUsage = 0;
  1388. }
  1389. if (fUpdateHistory)
  1390. {
  1391. if (SumTotalTime.QuadPart != 0)
  1392. {
  1393. g_KernelUsage = (BYTE) ((SumKernelTime.QuadPart * 100) / SumTotalTime.QuadPart);
  1394. }
  1395. else
  1396. {
  1397. g_KernelUsage = 0;
  1398. }
  1399. //
  1400. // Get the commit size
  1401. //
  1402. SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
  1403. Status = NtQuerySystemInformation(
  1404. SystemPerformanceInformation,
  1405. &PerfInfo,
  1406. sizeof(PerfInfo),
  1407. NULL);
  1408. if (!NT_SUCCESS(Status))
  1409. {
  1410. return;
  1411. }
  1412. g_MEMUsage = PerfInfo.CommittedPages * (g_PageSize / 1024);
  1413. MoveMemory((LPVOID) (g_pMEMHistory + 1),
  1414. (LPVOID) (g_pMEMHistory),
  1415. sizeof(BYTE) * (HIST_SIZE - 1) );
  1416. g_pMEMHistory[0] = (BYTE) (( g_MEMUsage * 100 ) / g_MEMMax );
  1417. }
  1418. }