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.

1478 lines
38 KiB

  1. /*****************************************************************************
  2. *
  3. * Grafdata.c - This module handles the non-drawing functions of the graph,
  4. * such as allocating linked structures and their memory, freeing it,
  5. * unlinking, starting and stopping the timer,
  6. * setting up the first graph (CPU), and all the numeric functions for
  7. * the different counter types.
  8. *
  9. * Microsoft Confidential
  10. * Copyright (c) 1992-1993 Microsoft Corporation
  11. *
  12. *
  13. ****************************************************************************/
  14. //==========================================================================//
  15. // Includes //
  16. //==========================================================================//
  17. #include <stdio.h> // for sprintf
  18. #include "perfmon.h" // main perfmon declarations
  19. #include "grafdata.h" // external declarations for this file
  20. #include <float.h> // for FLT_MAX constant
  21. #include "addline.h" // for AddLine, EditLine
  22. #include "counters.h" // for CounterEntry
  23. #include "graph.h" // for SizeGraphComponents
  24. #include "pmemory.h" // for MemoryXXX (mallloc-type) routines
  25. #include "perfdata.h" // for UpdateLines
  26. #include "playback.h" // for PlayingBackLog, PlaybackLines
  27. #include "legend.h"
  28. #include "system.h" // for SystemGet
  29. #include "utils.h"
  30. #include "line.h" // for LineFree
  31. #include "valuebar.h" // for StatusTimer
  32. #include "fileopen.h" // for FileGetName
  33. #include "fileutil.h" // for FileRead...
  34. #include "menuids.h" // for IDM_VIEWCHART
  35. #include "perfmops.h" // for ExportFileHeader
  36. #include "status.h" // for StatusLineReady
  37. extern BOOL SaveFileHandler(HWND hWnd,DWORD type) ;
  38. // this macro is used in doing a simple DDA (Digital Differential Analyzer)
  39. // * 10 + 5 is to make the result round up with .5
  40. #define DDA_DISTRIBUTE(TotalTics, numOfData) \
  41. ((TotalTics * 10 / numOfData) + 5) / 10
  42. #define szSmallValueFormat TEXT("%10.3f")
  43. #define szLargeValueFormat TEXT("%10.0f")
  44. //==========================================================================//
  45. // Local Data //
  46. //==========================================================================//
  47. //==========================================================================//
  48. // Local Functions //
  49. //==========================================================================//
  50. /****************************************************************************
  51. * eUpdateMinMaxAve -
  52. ****************************************************************************/
  53. void eUpdateMinMaxAve (FLOAT eValue, PLINESTRUCT pLineStruct, INT iValidValues,
  54. INT iTotalValidPoints, INT iDataPoint, INT gMaxPoints)
  55. {
  56. INT i ;
  57. INT iDataNum = iTotalValidPoints ;
  58. FLOAT eMin,
  59. eMax,
  60. eSum,
  61. eNewValue ;
  62. eMax = eMin = eValue ;
  63. if (PlayingBackLog())
  64. {
  65. eSum = (FLOAT) 0.0 ;
  66. }
  67. else
  68. {
  69. eSum = eValue ;
  70. }
  71. if (iValidValues == iTotalValidPoints)
  72. {
  73. for (i=0 ; i < iValidValues ; i++)
  74. {
  75. if (i == iDataPoint)
  76. {
  77. // skip the data point we are going to replace
  78. continue ;
  79. }
  80. eNewValue = pLineStruct->lnValues[i] ;
  81. eSum += eNewValue ;
  82. if (eNewValue > eMax)
  83. {
  84. eMax = eNewValue ;
  85. }
  86. if (eNewValue < eMin)
  87. {
  88. eMin = eNewValue ;
  89. }
  90. }
  91. }
  92. else
  93. {
  94. // special case when we start the new line in the middle of the chart
  95. for (i = iDataPoint, iTotalValidPoints-- ;
  96. iTotalValidPoints > 0 ;
  97. iTotalValidPoints-- )
  98. {
  99. i-- ;
  100. if (i < 0)
  101. {
  102. // for the wrap-around case..
  103. i = gMaxPoints - 1 ;
  104. }
  105. if (i == iDataPoint)
  106. {
  107. // skip the data point we are going to replace
  108. continue ;
  109. }
  110. eNewValue = pLineStruct->lnValues[i] ;
  111. eSum += eNewValue ;
  112. if (eNewValue > eMax)
  113. {
  114. eMax = eNewValue ;
  115. }
  116. if (eNewValue < eMin)
  117. {
  118. eMin = eNewValue ;
  119. }
  120. }
  121. }
  122. pLineStruct->lnMinValue = eMin ;
  123. pLineStruct->lnMaxValue = eMax ;
  124. if (iDataNum)
  125. {
  126. pLineStruct->lnAveValue = eSum / (FLOAT) iDataNum ;
  127. }
  128. else
  129. {
  130. pLineStruct->lnAveValue = (FLOAT) 0.0 ;
  131. }
  132. //clean up bogus (negative)values
  133. if (pLineStruct->lnMinValue < (FLOAT)0.0) {
  134. pLineStruct->lnMinValue = (FLOAT)0.0;
  135. }
  136. if (pLineStruct->lnMaxValue < (FLOAT)0.0) {
  137. pLineStruct->lnMaxValue = (FLOAT)0.0;
  138. }
  139. if (pLineStruct->lnAveValue < (FLOAT) 0.0) {
  140. pLineStruct->lnAveValue = (FLOAT) 0.0 ;
  141. }
  142. }
  143. // UpdateValueBarData is used to update the value bar data
  144. // It is called when the user switches to a diff. line from
  145. // the legned window.
  146. VOID UpdateValueBarData (PGRAPHSTRUCT pGraph)
  147. {
  148. PLINESTRUCT pCurrentGraphLine ;
  149. INT KnownValue,
  150. MaxValues,
  151. iValidValues,
  152. iDataPoint ;
  153. FLOAT eValue ;
  154. pCurrentGraphLine = CurrentGraphLine (hWndGraph) ;
  155. if (!pCurrentGraphLine || pCurrentGraphLine->bFirstTime)
  156. {
  157. // we have not collect enough samples
  158. return ;
  159. }
  160. KnownValue = pGraph->gKnownValue ;
  161. MaxValues = pGraph->gMaxValues ;
  162. // The valid values is the number of valid entries in the
  163. // data buffer. After we wrap the buffer, all the values are
  164. // valid.
  165. iValidValues = pGraph->gTimeLine.iValidValues ;
  166. // Get the index to the data point we are updating.
  167. iDataPoint = KnownValue % MaxValues ;
  168. eValue = pCurrentGraphLine->lnValues[iDataPoint] ;
  169. // get the statistical data for this line
  170. eUpdateMinMaxAve(eValue, pCurrentGraphLine,
  171. iValidValues, pCurrentGraphLine->lnValidValues,
  172. iDataPoint, MaxValues) ;
  173. } // UpdateValueBarData
  174. VOID UpdateLGData (PGRAPHSTRUCT pGraph)
  175. {
  176. PLINESTRUCT pLine ;
  177. PLINESTRUCT pCurrentGraphLine ;
  178. INT KnownValue,
  179. MaxValues,
  180. iValidValues,
  181. iDataPoint ;
  182. FLOAT eValue ;
  183. // Known Value is the where data is placed in the buffer.
  184. pGraph->gKnownValue++;
  185. KnownValue = pGraph->gKnownValue ;
  186. // Update the high water mark for valid data in the lnValues
  187. // (aka DataPoint) buffer.
  188. MaxValues = pGraph->gMaxValues ;
  189. // The valid values is the number of valid entries in the
  190. // data buffer. After we wrap the buffer, all the values are
  191. // valid.
  192. iValidValues = pGraph->gTimeLine.iValidValues ;
  193. if (iValidValues < MaxValues)
  194. iValidValues = (KnownValue % MaxValues) + 1 ;
  195. pGraph->gTimeLine.iValidValues = iValidValues ;
  196. // Get the index to the data point we are updating.
  197. iDataPoint = KnownValue % MaxValues ;
  198. // loop through lines,
  199. // If one of the lines is highlighted then do the calculations
  200. // for average, min, & max on that line.
  201. pCurrentGraphLine = CurrentGraphLine (hWndGraph) ;
  202. for (pLine=pGraph->pLineFirst; pLine; pLine=pLine->pLineNext)
  203. { // for
  204. if (pLine->bFirstTime)
  205. {
  206. // skip until we have collect enough samples to plot the first data
  207. continue ;
  208. }
  209. if (pLine->lnValidValues < MaxValues)
  210. {
  211. (pLine->lnValidValues)++ ;
  212. }
  213. // Get the new value for this line.
  214. eValue = CounterEntry (pLine) ;
  215. if (pLine == pCurrentGraphLine)
  216. { // if
  217. // get the statistical data for this line
  218. eUpdateMinMaxAve (eValue, pLine,
  219. iValidValues, pLine->lnValidValues,
  220. iDataPoint, MaxValues) ;
  221. } // if
  222. // Now put the new value into the data array
  223. pLine->lnValues[iDataPoint] = eValue ;
  224. }
  225. GetLocalTime (&(pGraph->pDataTime[iDataPoint])) ;
  226. } // UpdateLGData
  227. BOOL HandleGraphTimer (void)
  228. {
  229. PGRAPHSTRUCT pGraph;
  230. //NOTE: get a strategy for these "no-go" states
  231. if (!(pGraph = pGraphs) || !pGraphs->pSystemFirst)
  232. return(FALSE);
  233. if (!UpdateLines(&(pGraphs->pSystemFirst), pGraphs->pLineFirst))
  234. return (TRUE) ;
  235. UpdateLGData(pGraph);
  236. return(TRUE);
  237. }
  238. VOID ClearGraphTimer(PGRAPHSTRUCT pGraph)
  239. {
  240. KillTimer(pGraph->hWnd, GRAPH_TIMER_ID);
  241. }
  242. VOID SetGraphTimer(PGRAPHSTRUCT pGraph)
  243. {
  244. SetTimer(pGraph->hWnd, GRAPH_TIMER_ID, pGraph->gInterval, NULL) ;
  245. }
  246. VOID ResetGraphTimer(PGRAPHSTRUCT pGraph)
  247. {
  248. KillTimer(pGraph->hWnd, GRAPH_TIMER_ID);
  249. SetGraphTimer(pGraph);
  250. }
  251. VOID GetGraphConfig(PGRAPHSTRUCT pGraph)
  252. {
  253. LoadRefreshSettings(pGraph);
  254. LoadLineGraphSettings(pGraph);
  255. // Init the structure
  256. pGraph->pLineFirst = NULL;
  257. //NOTE: put the rest of this in Config
  258. pGraph->gOptions.bLegendChecked = TRUE;
  259. pGraph->gOptions.bMenuChecked = TRUE;
  260. pGraph->gOptions.bLabelsChecked = TRUE;
  261. pGraph->gOptions.bVertGridChecked = FALSE;
  262. pGraph->gOptions.bHorzGridChecked = FALSE;
  263. pGraph->gOptions.bStatusBarChecked = TRUE;
  264. pGraph->gOptions.GraphVGrid = TRUE;
  265. pGraph->gOptions.GraphHGrid = TRUE;
  266. pGraph->gOptions.HistVGrid = TRUE;
  267. pGraph->gOptions.HistHGrid = TRUE;
  268. pGraph->gOptions.iGraphOrHistogram = LINE_GRAPH; // vs. BAR_GRAPH
  269. pGraph->gOptions.iVertMax = DEF_GRAPH_VMAX;
  270. return;
  271. }
  272. BOOL InsertGraph (HWND hWnd)
  273. {
  274. PGRAPHSTRUCT pGraph;
  275. pGraph = MemoryAllocate (sizeof (GRAPHSTRUCT)) ;
  276. if (!pGraph)
  277. return (FALSE) ;
  278. pGraphs = pGraph;
  279. GetGraphConfig(pGraph);
  280. pGraph->bManualRefresh = FALSE ;
  281. // there's at least one place where the [DEFAULT_MAX_VALUES] entry is
  282. // accessed when the index should stop at [DEFAULT_MAX_VALUES -1].
  283. // rather than try to find all the places this index is used it's easier
  284. // and safer just to make the array large enough to accomodate this
  285. // "oversight"
  286. pGraph->gMaxValues = DEFAULT_MAX_VALUES;
  287. pGraph->pptDataPoints =
  288. (PPOINT) MemoryAllocate (sizeof (POINT) * (pGraph->gMaxValues + 1)) ;
  289. pGraph->pDataTime =
  290. (SYSTEMTIME *) MemoryAllocate (sizeof(SYSTEMTIME) * (pGraph->gMaxValues + 1)) ;
  291. pGraph->hWnd = hWnd ;
  292. pGraph->bModified = FALSE ;
  293. pGraph->Visual.iColorIndex = 0 ;
  294. pGraph->Visual.iWidthIndex = 0 ;
  295. pGraph->Visual.iStyleIndex = 0 ;
  296. return(TRUE) ;
  297. }
  298. void PlaybackSetGraphLines (HWND hWndChart,
  299. PLINE pLineFirst,
  300. int iDisplayTic,
  301. int iLogTic,
  302. BOOL CalcData)
  303. {
  304. PLINE pLine ;
  305. FLOAT eValue ;
  306. for (pLine = pLineFirst ;
  307. pLine ;
  308. pLine = pLine->pLineNext)
  309. { // for
  310. eValue = CounterEntry (pLine) ;
  311. pLine->lnValues[iDisplayTic] = eValue ;
  312. pLine->aiLogIndexes[iDisplayTic] = iLogTic ;
  313. // only need to do this on request.
  314. if (CalcData)
  315. {
  316. eUpdateMinMaxAve (eValue, pLine, iDisplayTic, iDisplayTic,
  317. iDisplayTic, iDisplayTic) ;
  318. } // if
  319. } // for
  320. } // PlaybackSetGraphLines
  321. BOOL ChartInsertLine (PGRAPHSTRUCT pGraph,
  322. PLINE pLine)
  323. /*
  324. Effect: Insert the line pLine into the graph pGraph and
  325. allocate space for the graph's number of values.
  326. Returns: Whether the line could be added and space allocated.
  327. See Also: LineAllocate (line.c), ChartDeleteLine.
  328. */
  329. { // ChartInsertLine
  330. PLINE pLineEquivalent ;
  331. INT i ;
  332. FLOAT *pTempPts;
  333. HPEN tempPen ;
  334. pGraph->bModified = TRUE ;
  335. pLineEquivalent = FindEquivalentLine (pLine, pGraph->pLineFirst) ;
  336. if (pLineEquivalent)
  337. {
  338. if (bMonitorDuplicateInstances) {
  339. pLine->dwInstanceIndex = pLineEquivalent->dwInstanceIndex + 1;
  340. } else {
  341. pLineEquivalent->Visual = pLine->Visual ;
  342. pLineEquivalent->iScaleIndex = pLine->iScaleIndex ;
  343. pLineEquivalent->eScale = pLine->eScale ;
  344. tempPen = pLineEquivalent->hPen ;
  345. pLineEquivalent->hPen = pLine->hPen ;
  346. pLine->hPen = tempPen ;
  347. return FALSE ;
  348. }
  349. }
  350. if (!pGraph->pLineFirst && !PlayingBackLog())
  351. {
  352. SetGraphTimer (pGraph) ;
  353. }
  354. if (!SystemAdd (&pGraph->pSystemFirst, pLine->lnSystemName,pGraph->hWnd))
  355. return FALSE;
  356. LineAppend (&pGraph->pLineFirst, pLine) ;
  357. pLine->lnMinValue = FLT_MAX ;
  358. pLine->lnMaxValue = - FLT_MAX ;
  359. pLine->lnAveValue = 0.0F ;
  360. pLine->lnValidValues = 0 ;
  361. pLine->lnValues =
  362. (FLOAT *) MemoryAllocate (sizeof (FLOAT) * (pGraph->gMaxValues + 1)) ;
  363. for (i = pGraph->gMaxValues, pTempPts = pLine->lnValues ;
  364. (i > 0) && (pTempPts != NULL) ;
  365. i-- )
  366. {
  367. *pTempPts++ = (FLOAT) 0.0 ;
  368. }
  369. if (PlayingBackLog ())
  370. {
  371. pLine->aiLogIndexes =
  372. (int *) MemoryAllocate (sizeof (LONG) * (pGraph->gMaxValues + 1)) ;
  373. }
  374. // Add the line to the legend, resize the legend window, and then
  375. // select the new line as the current legend item. Do it in this
  376. // sequence to avoid the legend scroll bar momentarily appearing and
  377. // then disappearing, since the resize will obviate the scroll bar.
  378. LegendAddItem (hWndGraphLegend, pLine) ;
  379. if (!bDelayAddAction)
  380. {
  381. SizeGraphComponents (hWndGraph) ;
  382. LegendSetSelection (hWndGraphLegend,
  383. LegendNumItems (hWndGraphLegend) - 1) ;
  384. if (PlayingBackLog ()) PlaybackChart (pGraph->hWnd) ;
  385. }
  386. return (TRUE) ;
  387. } // ChartInsertLine
  388. VOID ChartDeleteLine (PGRAPHSTRUCT pGraph,
  389. PLINESTRUCT pLine)
  390. {
  391. PLINESTRUCT npLine;
  392. pGraph->bModified = TRUE ;
  393. if (pGraph->pLineFirst == pLine)
  394. pGraph->pLineFirst = pLine->pLineNext;
  395. else
  396. {
  397. for (npLine = pGraph->pLineFirst; npLine; npLine = npLine->pLineNext)
  398. {
  399. if (npLine->pLineNext == pLine)
  400. npLine->pLineNext = pLine->pLineNext;
  401. }
  402. }
  403. if (!pGraph->pLineFirst)
  404. {
  405. ResetGraph (pGraph) ;
  406. }
  407. else
  408. {
  409. BuildValueListForSystems (
  410. pGraph->pSystemFirst,
  411. pGraph->pLineFirst) ;
  412. }
  413. // Delete the legend entry for this line.
  414. // If the line was highlighted then this will undo the highlight.
  415. LegendDeleteItem (hWndGraphLegend, pLine) ;
  416. LineFree (pLine) ;
  417. SizeGraphComponents (hWndGraph) ;
  418. }
  419. void ClearGraphDisplay (PGRAPHSTRUCT pGraph)
  420. {
  421. PLINESTRUCT pLine;
  422. // reset the timeline data
  423. // pGraph->gKnownValue = -1 ;
  424. pGraph->gKnownValue = 0 ;
  425. pGraph->gTimeLine.iValidValues = 0 ;
  426. pGraph->gTimeLine.xLastTime = 0 ;
  427. memset (pGraph->pDataTime, 0, sizeof(SYSTEMTIME) * (pGraph->gMaxValues + 1)) ;
  428. // loop through lines,
  429. // If one of the lines is highlighted then do the calculations
  430. // for average, min, & max on that line.
  431. for (pLine=pGraph->pLineFirst; pLine; pLine=pLine->pLineNext)
  432. { // for
  433. pLine->bFirstTime = 2 ;
  434. pLine->lnMinValue = FLT_MAX ;
  435. pLine->lnMaxValue = - FLT_MAX ;
  436. pLine->lnAveValue = 0.0F ;
  437. pLine->lnValidValues = 0 ;
  438. memset (pLine->lnValues, 0, sizeof(FLOAT) * (pGraph->gMaxValues + 1)) ;
  439. }
  440. StatusTimer (hWndGraphStatus, TRUE) ;
  441. WindowInvalidate (hWndGraphDisplay) ;
  442. }
  443. void ResetGraphView (HWND hWndGraph)
  444. {
  445. PGRAPHSTRUCT pGraph ;
  446. pGraph = GraphData (hWndGraph) ;
  447. if (!pGraph)
  448. {
  449. return ;
  450. }
  451. ChangeSaveFileName (NULL, IDM_VIEWCHART) ;
  452. if (pGraph->pSystemFirst)
  453. {
  454. ResetGraph (pGraph) ;
  455. }
  456. } // ResetGraphView
  457. void ResetGraph (PGRAPHSTRUCT pGraph)
  458. {
  459. ClearGraphTimer (pGraph) ;
  460. ClearLegend (hWndGraphLegend) ;
  461. if (pGraph->pLineFirst)
  462. {
  463. FreeLines (pGraph->pLineFirst) ;
  464. pGraph->pLineFirst = NULL ;
  465. }
  466. if (pGraph->pSystemFirst)
  467. {
  468. FreeSystems (pGraph->pSystemFirst) ;
  469. pGraph->pSystemFirst = NULL ;
  470. }
  471. // pGraph->gKnownValue = -1 ;
  472. pGraph->gKnownValue = 0 ;
  473. pGraph->gTimeLine.iValidValues = 0 ;
  474. pGraph->gTimeLine.xLastTime = 0 ;
  475. // reset visual data
  476. pGraph->Visual.iColorIndex = 0 ;
  477. pGraph->Visual.iWidthIndex = 0 ;
  478. pGraph->Visual.iStyleIndex = 0 ;
  479. memset (pGraph->pDataTime, 0, sizeof(SYSTEMTIME) * (pGraph->gMaxValues + 1)) ;
  480. SizeGraphComponents (hWndGraph) ;
  481. InvalidateRect(hWndGraph, NULL, TRUE) ;
  482. }
  483. void PlaybackChart (HWND hWndChart)
  484. { // PlaybackChart
  485. int iDisplayTics ; // num visual points to display
  486. int iDisplayTic ;
  487. int iLogTic ;
  488. int iLogTicsMove ;
  489. BOOL bFirstTime = TRUE;
  490. int iLogTicsRemaining ;
  491. if (!pGraphs->pLineFirst)
  492. {
  493. // no line to playback
  494. return ;
  495. }
  496. iLogTicsRemaining = PlaybackLog.iSelectedTics ;
  497. // we only have iDisplayTics-1 points since
  498. // we have to use the first two sample points to
  499. // get the first data points.
  500. if (iLogTicsRemaining <= pGraphs->gMaxValues)
  501. {
  502. iDisplayTics = iLogTicsRemaining ;
  503. pGraphs->gTimeLine.iValidValues = iDisplayTics - 1 ;
  504. }
  505. else
  506. {
  507. iDisplayTics = pGraphs->gMaxValues ;
  508. pGraphs->gTimeLine.iValidValues = iDisplayTics ;
  509. }
  510. iDisplayTic = -1 ;
  511. iLogTic = PlaybackLog.StartIndexPos.iPosition ;
  512. while (iDisplayTics)
  513. {
  514. PlaybackLines (pGraphs->pSystemFirst,
  515. pGraphs->pLineFirst,
  516. iLogTic) ;
  517. if (bFirstTime)
  518. {
  519. bFirstTime = FALSE ;
  520. // get the second sample data to form the first data point
  521. iLogTic++ ;
  522. iLogTicsRemaining-- ;
  523. PlaybackLines (pGraphs->pSystemFirst,
  524. pGraphs->pLineFirst,
  525. iLogTic) ;
  526. }
  527. iDisplayTic++ ;
  528. PlaybackSetGraphLines (hWndChart, pGraphs->pLineFirst,
  529. iDisplayTic, iLogTic, (iDisplayTics == 1)) ;
  530. // setup DDA to get the index of the next sample point
  531. iLogTicsMove = DDA_DISTRIBUTE (iLogTicsRemaining, iDisplayTics) ;
  532. iLogTicsRemaining -= iLogTicsMove ;
  533. iLogTic += iLogTicsMove ;
  534. iDisplayTics-- ;
  535. } // while
  536. // point to the last value for valuebar display
  537. pGraphs->gKnownValue = iDisplayTic ;
  538. } // PlaybackChart
  539. #if 0
  540. PLINESTRUCT CurrentGraphLine (HWND hWndGraph)
  541. { // CurrentGraphLine
  542. UNREFERENCED_PARAMETER (hWndGraph) ;
  543. return (LegendCurrentLine (hWndGraphLegend)) ;
  544. }
  545. #endif
  546. BOOL AddChart (HWND hWndParent)
  547. {
  548. PLINE pCurrentLine = CurrentGraphLine (hWndGraph) ;
  549. return (AddLine (hWndParent,
  550. &(pGraphs->pSystemFirst),
  551. &(pGraphs->Visual),
  552. pCurrentLine ? pCurrentLine->lnSystemName : NULL,
  553. LineTypeChart)) ;
  554. }
  555. BOOL EditChart (HWND hWndParent)
  556. { // EditChart
  557. return (EditLine (hWndParent,
  558. &(pGraphs->pSystemFirst),
  559. CurrentGraphLine (hWndGraph),
  560. LineTypeChart)) ;
  561. }
  562. void GraphAddAction ()
  563. {
  564. PGRAPHSTRUCT pGraph ;
  565. pGraph = GraphData (hWndGraph) ;
  566. SizeGraphComponents (hWndGraph) ;
  567. LegendSetSelection (hWndGraphLegend,
  568. LegendNumItems (hWndGraphLegend) - 1) ;
  569. if (PlayingBackLog ())
  570. PlaybackChart (pGraph->hWnd) ;
  571. }
  572. BOOL OpenChartVer1 (HANDLE hFile,
  573. DISKCHART *pDiskChart,
  574. PGRAPHSTRUCT pGraph)
  575. { // OpenChartVer1
  576. bDelayAddAction = TRUE ;
  577. pGraph->Visual = pDiskChart->Visual ;
  578. pGraph->gOptions = pDiskChart->gOptions ;
  579. pGraph->gMaxValues = pDiskChart->gMaxValues ;
  580. pGraph->bManualRefresh = pDiskChart->bManualRefresh ;
  581. pGraphs->gInterval = (INT) (pGraph->gOptions.eTimeInterval * (FLOAT) 1000.0) ;
  582. ReadLines (hFile, pDiskChart->dwNumLines,
  583. &(pGraph->pSystemFirst), &(pGraph->pLineFirst), IDM_VIEWCHART) ;
  584. bDelayAddAction = FALSE ;
  585. GraphAddAction () ;
  586. return (TRUE) ;
  587. } // OpenChartVer1
  588. BOOL OpenChart (HWND hWndGraph,
  589. HANDLE hFile,
  590. DWORD dwMajorVersion,
  591. DWORD dwMinorVersion,
  592. BOOL bChartFile)
  593. { // OpenChart
  594. PGRAPHSTRUCT pGraph ;
  595. DISKCHART DiskChart ;
  596. BOOL bSuccess = TRUE ;
  597. pGraph = pGraphs ;
  598. if (!pGraph)
  599. {
  600. bSuccess = FALSE ;
  601. goto Exit0 ;
  602. }
  603. if (!FileRead (hFile, &DiskChart, sizeof (DISKCHART)))
  604. {
  605. bSuccess = FALSE ;
  606. goto Exit0 ;
  607. }
  608. switch (dwMajorVersion)
  609. {
  610. case (1):
  611. SetHourglassCursor() ;
  612. ResetGraphView (hWndGraph) ;
  613. OpenChartVer1 (hFile, &DiskChart, pGraph) ;
  614. // change to chart view if we are opening a
  615. // chart file
  616. if (bChartFile && iPerfmonView != IDM_VIEWCHART)
  617. {
  618. SendMessage (hWndMain, WM_COMMAND, (LONG)IDM_VIEWCHART, 0L) ;
  619. }
  620. if (iPerfmonView == IDM_VIEWCHART)
  621. {
  622. SetPerfmonOptions (&DiskChart.perfmonOptions) ;
  623. }
  624. SetArrowCursor() ;
  625. break ;
  626. } // switch
  627. Exit0:
  628. if (bChartFile)
  629. {
  630. CloseHandle (hFile) ;
  631. }
  632. return (bSuccess) ;
  633. } // OpenChart
  634. BOOL SaveChart (HWND hWndGraph, HANDLE hInputFile, BOOL bGetFileName)
  635. {
  636. PGRAPHSTRUCT pGraph ;
  637. PLINE pLine ;
  638. HANDLE hFile ;
  639. DISKCHART DiskChart ;
  640. PERFFILEHEADER FileHeader ;
  641. TCHAR szFileName [256] ;
  642. BOOL newFileName = FALSE ;
  643. if (hInputFile)
  644. {
  645. // use the input file handle if it is available
  646. // this is the case for saving workspace data
  647. hFile = hInputFile ;
  648. }
  649. else
  650. {
  651. if (pChartFullFileName)
  652. {
  653. lstrcpy (szFileName, pChartFullFileName) ;
  654. }
  655. if (bGetFileName || pChartFullFileName == NULL)
  656. {
  657. // if (!pChartFullFileName)
  658. // {
  659. // StringLoad (IDS_GRAPH_FNAME, szFileName) ;
  660. // }
  661. if (!FileGetName (hWndGraph, IDS_CHARTFILE, szFileName))
  662. {
  663. return (FALSE) ;
  664. }
  665. newFileName = TRUE ;
  666. }
  667. hFile = FileHandleCreate (szFileName) ;
  668. if (hFile && hFile != INVALID_HANDLE_VALUE && newFileName)
  669. {
  670. ChangeSaveFileName (szFileName, IDM_VIEWCHART) ;
  671. }
  672. else if (!hFile || hFile == INVALID_HANDLE_VALUE)
  673. {
  674. DlgErrorBox (hWndGraph, ERR_CANT_OPEN, szFileName) ;
  675. }
  676. }
  677. if (!hFile || hFile == INVALID_HANDLE_VALUE)
  678. return (FALSE) ;
  679. pGraph = pGraphs ;
  680. if (!pGraph)
  681. {
  682. if (!hInputFile || hInputFile == INVALID_HANDLE_VALUE)
  683. {
  684. CloseHandle (hFile) ;
  685. }
  686. return (FALSE) ;
  687. }
  688. if (!hInputFile || hInputFile == INVALID_HANDLE_VALUE)
  689. {
  690. // only need to write file header if not workspace
  691. memset (&FileHeader, 0, sizeof (FileHeader)) ;
  692. lstrcpy (FileHeader.szSignature, szPerfChartSignature) ;
  693. FileHeader.dwMajorVersion = ChartMajorVersion ;
  694. FileHeader.dwMinorVersion = ChartMinorVersion ;
  695. if (!FileWrite (hFile, &FileHeader, sizeof (PERFFILEHEADER)))
  696. {
  697. goto Exit0 ;
  698. }
  699. }
  700. DiskChart.Visual = pGraph->Visual ;
  701. DiskChart.gOptions = pGraph->gOptions ;
  702. DiskChart.gMaxValues = pGraph->gMaxValues ;
  703. DiskChart.dwNumLines = NumLines (pGraph->pLineFirst) ;
  704. DiskChart.bManualRefresh = pGraph->bManualRefresh ;
  705. DiskChart.perfmonOptions = Options ;
  706. if (!FileWrite (hFile, &DiskChart, sizeof (DISKCHART)))
  707. {
  708. goto Exit0 ;
  709. }
  710. for (pLine = pGraph->pLineFirst ;
  711. pLine ;
  712. pLine = pLine->pLineNext)
  713. { // for
  714. if (!WriteLine (pLine, hFile))
  715. {
  716. goto Exit0 ;
  717. }
  718. } // for
  719. if (!hInputFile || hInputFile == INVALID_HANDLE_VALUE)
  720. {
  721. CloseHandle (hFile) ;
  722. }
  723. return (TRUE) ;
  724. Exit0:
  725. if (!hInputFile || hInputFile == INVALID_HANDLE_VALUE)
  726. {
  727. CloseHandle (hFile) ;
  728. // only need to report error if not workspace
  729. DlgErrorBox (hWndGraph, ERR_SETTING_FILE, szFileName) ;
  730. }
  731. return (FALSE) ;
  732. } // SaveChart
  733. #define TIME_TO_WRITE 2
  734. BOOL ExportChartLabels (HANDLE hFile, PGRAPHSTRUCT pGraph)
  735. {
  736. TCHAR UnicodeBuff [LongTextLen] ;
  737. CHAR TempBuff [LongTextLen * 2] ;
  738. int StringLen ;
  739. PLINESTRUCT pLine;
  740. int TimeToWriteFile ;
  741. int iIndex ;
  742. LPTSTR lpItem = NULL;
  743. for (iIndex = 0 ; iIndex < 5 ; iIndex++)
  744. {
  745. // for iIndex == 0, get counter name
  746. // for iIndex == 1, get instance name
  747. // for iIndex == 2, get parent name
  748. // for iIndex == 3, get object name
  749. // for iIndex == 4, get computer name
  750. if (iIndex == 4)
  751. {
  752. // the last label field, write date/time labels
  753. strcpy (TempBuff, LineEndStr) ;
  754. StringLen = strlen (TempBuff) ;
  755. StringLoad (IDS_EXPORT_DATE, UnicodeBuff) ;
  756. ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
  757. strcat (TempBuff, pDelimiter) ;
  758. StringLen = strlen (TempBuff) ;
  759. StringLoad (IDS_EXPORT_TIME, UnicodeBuff) ;
  760. ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
  761. strcat (TempBuff, pDelimiter) ;
  762. StringLen = strlen (TempBuff) ;
  763. }
  764. else
  765. {
  766. strcpy (TempBuff, LineEndStr) ;
  767. strcat (TempBuff, pDelimiter) ;
  768. strcat (TempBuff, pDelimiter) ;
  769. StringLen = strlen (TempBuff) ;
  770. }
  771. TimeToWriteFile = 0 ;
  772. for (pLine=pGraph->pLineFirst; pLine; pLine=pLine->pLineNext)
  773. {
  774. switch (iIndex)
  775. {
  776. case 0:
  777. lpItem = (LPTSTR) pLine->lnCounterName ;
  778. break ;
  779. case 1:
  780. lpItem = (LPTSTR) pLine->lnInstanceName ;
  781. break ;
  782. case 2:
  783. lpItem = (LPTSTR) pLine->lnPINName ;
  784. break ;
  785. case 3:
  786. lpItem = (LPTSTR) pLine->lnObjectName ;
  787. break ;
  788. case 4:
  789. lpItem = (LPTSTR) pLine->lnSystemName ;
  790. break ;
  791. }
  792. if (lpItem)
  793. {
  794. ConvertUnicodeStr (&TempBuff[StringLen], lpItem) ;
  795. }
  796. else
  797. {
  798. TempBuff[StringLen] = '\0' ;
  799. }
  800. strcat (TempBuff, pDelimiter);
  801. StringLen = strlen (TempBuff) ;
  802. if (++TimeToWriteFile > TIME_TO_WRITE)
  803. {
  804. // better write the buffers before they overflow.
  805. // there are better ways to check for overflow
  806. // but this is good enough
  807. if (!FileWrite (hFile, TempBuff, StringLen))
  808. {
  809. goto Exit0 ;
  810. }
  811. StringLen = TimeToWriteFile = 0 ;
  812. }
  813. } // for each line
  814. if (StringLen)
  815. {
  816. // write the last block of data
  817. if (!FileWrite (hFile, TempBuff, StringLen))
  818. {
  819. goto Exit0 ;
  820. }
  821. }
  822. } // for iIndex
  823. return (TRUE) ;
  824. Exit0:
  825. return (FALSE) ;
  826. } // ExportChartLabels
  827. BOOL ExportLogChart (HANDLE hFile, PGRAPHSTRUCT pGraph)
  828. {
  829. TCHAR UnicodeBuff [LongTextLen] ;
  830. CHAR TempBuff [LongTextLen * 2] ;
  831. int StringLen ;
  832. PLINESTRUCT pLine;
  833. int TimeToWriteFile ;
  834. FLOAT eValue ;
  835. int iLogTic ;
  836. BOOL bFirstTime = TRUE ;
  837. SYSTEMTIME LogSystemTime ;
  838. LOGPOSITION LogPosition ;
  839. iLogTic = PlaybackLog.StartIndexPos.iPosition ;
  840. // we have to export every point from the log file
  841. for ( ; iLogTic <= PlaybackLog.StopIndexPos.iPosition ; iLogTic++)
  842. {
  843. PlaybackLines (pGraphs->pSystemFirst,
  844. pGraphs->pLineFirst,
  845. iLogTic) ;
  846. if (!bFirstTime)
  847. {
  848. // export the values
  849. TimeToWriteFile = 0 ;
  850. if (!LogPositionN (iLogTic, &LogPosition))
  851. {
  852. goto Exit0 ;
  853. }
  854. LogPositionSystemTime (&LogPosition, &LogSystemTime) ;
  855. strcpy (TempBuff, LineEndStr) ;
  856. StringLen = strlen (TempBuff) ;
  857. SystemTimeDateString (&LogSystemTime, UnicodeBuff) ;
  858. ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
  859. strcat (TempBuff, pDelimiter) ;
  860. StringLen = strlen (TempBuff) ;
  861. SystemTimeTimeString (&LogSystemTime, UnicodeBuff, FALSE) ;
  862. ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
  863. strcat (TempBuff, pDelimiter) ;
  864. StringLen = strlen (TempBuff) ;
  865. for (pLine=pGraph->pLineFirst; pLine; pLine=pLine->pLineNext)
  866. {
  867. eValue = CounterEntry (pLine) ;
  868. TSPRINTF (UnicodeBuff,
  869. eValue > (FLOAT)999999.0 ?
  870. szLargeValueFormat : szSmallValueFormat,
  871. eValue) ;
  872. ConvertDecimalPoint (UnicodeBuff) ;
  873. ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
  874. strcat (TempBuff, pDelimiter) ;
  875. StringLen = strlen (TempBuff) ;
  876. if (++TimeToWriteFile > TIME_TO_WRITE)
  877. {
  878. if (!FileWrite (hFile, TempBuff, StringLen))
  879. {
  880. goto Exit0 ;
  881. }
  882. StringLen = TimeToWriteFile = 0 ;
  883. TempBuff[0] = '\0' ;
  884. }
  885. }
  886. if (StringLen)
  887. {
  888. if (!FileWrite (hFile, TempBuff, StringLen))
  889. {
  890. goto Exit0 ;
  891. }
  892. }
  893. }
  894. else
  895. {
  896. // skip the first data point since we
  897. // need 2 points to form the first value
  898. bFirstTime = FALSE ;
  899. }
  900. }
  901. return (TRUE) ;
  902. Exit0:
  903. return (FALSE) ;
  904. } // ExportLogChart
  905. BOOL ExportLineValue (HANDLE hFile, PGRAPHSTRUCT pGraph,
  906. int CurrentIndex, int iDataPoint)
  907. {
  908. TCHAR UnicodeBuff [MiscTextLen] ;
  909. CHAR TempBuff [LongTextLen] ;
  910. int StringLen ;
  911. PLINESTRUCT pLine;
  912. int MaxValues ;
  913. int TimeToWriteFile ;
  914. SYSTEMTIME *pSystemTime ;
  915. BOOL ValidValue ;
  916. pSystemTime = pGraph->pDataTime ;
  917. pSystemTime += CurrentIndex ;
  918. if (pSystemTime->wYear == 0 && pSystemTime->wYear == 0)
  919. {
  920. // ignore value that has 0 system time
  921. return (TRUE) ;
  922. }
  923. MaxValues = pGraph->gMaxValues ;
  924. strcpy (TempBuff, LineEndStr) ;
  925. StringLen = strlen (TempBuff) ;
  926. SystemTimeDateString (pSystemTime, UnicodeBuff) ;
  927. ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
  928. strcat (TempBuff, pDelimiter) ;
  929. StringLen = strlen (TempBuff) ;
  930. SystemTimeTimeString (pSystemTime, UnicodeBuff, FALSE) ;
  931. ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
  932. strcat (TempBuff, pDelimiter) ;
  933. StringLen = strlen (TempBuff) ;
  934. TimeToWriteFile = 0 ;
  935. for (pLine=pGraph->pLineFirst; pLine; pLine=pLine->pLineNext)
  936. {
  937. if (!pLine->bFirstTime)
  938. {
  939. ValidValue = FALSE ;
  940. // check if this is a valid value
  941. if (pLine->lnValidValues == MaxValues)
  942. {
  943. // this is the simple case where we have filled up
  944. // the whole buffer
  945. ValidValue = TRUE ;
  946. }
  947. else if (pLine->lnValidValues <= iDataPoint)
  948. {
  949. if (CurrentIndex <= iDataPoint &&
  950. CurrentIndex > iDataPoint - pLine->lnValidValues)
  951. {
  952. ValidValue = TRUE ;
  953. }
  954. }
  955. else
  956. {
  957. if (CurrentIndex <= iDataPoint ||
  958. CurrentIndex > (MaxValues - pLine->lnValidValues + iDataPoint))
  959. {
  960. // this is the case when we start the new line in the middle
  961. // and data buffer has been wrap-around.
  962. ValidValue = TRUE ;
  963. }
  964. }
  965. // only export the data when we determine it is valid
  966. if (ValidValue)
  967. {
  968. TSPRINTF (UnicodeBuff,
  969. pLine->lnValues[CurrentIndex] > (FLOAT)999999.0 ?
  970. szLargeValueFormat : szSmallValueFormat,
  971. pLine->lnValues[CurrentIndex]) ;
  972. ConvertDecimalPoint (UnicodeBuff) ;
  973. ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
  974. }
  975. }
  976. strcat (TempBuff, pDelimiter) ;
  977. StringLen = strlen (TempBuff) ;
  978. if (++TimeToWriteFile > TIME_TO_WRITE)
  979. {
  980. // better write the buffers before they overflow.
  981. // there are better ways to check for overflow
  982. // but this is good enough
  983. if (!FileWrite (hFile, TempBuff, StringLen))
  984. {
  985. goto Exit0 ;
  986. }
  987. StringLen = TimeToWriteFile = 0 ;
  988. TempBuff[0] = '\0' ;
  989. }
  990. }
  991. if (StringLen)
  992. {
  993. // write the last block of data
  994. if (!FileWrite (hFile, TempBuff, StringLen))
  995. {
  996. goto Exit0 ;
  997. }
  998. }
  999. return (TRUE) ;
  1000. Exit0:
  1001. return (FALSE) ;
  1002. } // ExportLineValue
  1003. BOOL ExportCurrentChart (HANDLE hFile, PGRAPHSTRUCT pGraph)
  1004. {
  1005. int KnownValue,
  1006. MaxValues,
  1007. iValidValues,
  1008. iDataPoint ;
  1009. BOOL SimpleCase = FALSE ;
  1010. int iIndex ;
  1011. MaxValues = pGraph->gMaxValues ;
  1012. KnownValue = pGraph->gKnownValue ;
  1013. iValidValues = pGraph->gTimeLine.iValidValues ;
  1014. if (iValidValues < MaxValues)
  1015. {
  1016. // data have not wrapped around, so the oldest time
  1017. // is started at 0.
  1018. SimpleCase = TRUE ;
  1019. iValidValues = (KnownValue % MaxValues) + 1 ;
  1020. }
  1021. iDataPoint = KnownValue % MaxValues ;
  1022. if (!SimpleCase)
  1023. {
  1024. for (iIndex = iDataPoint+1 ; iIndex < MaxValues ; iIndex++)
  1025. {
  1026. if (!ExportLineValue (hFile, pGraph, iIndex, iDataPoint))
  1027. {
  1028. goto Exit0 ;
  1029. }
  1030. }
  1031. }
  1032. for (iIndex = 0 ; iIndex <= iDataPoint ; iIndex++)
  1033. {
  1034. if (!ExportLineValue (hFile, pGraph, iIndex, iDataPoint))
  1035. {
  1036. goto Exit0 ;
  1037. }
  1038. }
  1039. return (TRUE) ;
  1040. Exit0:
  1041. return (FALSE) ;
  1042. } // ExportCurrentChart
  1043. void ExportChart (void)
  1044. {
  1045. PGRAPHSTRUCT pGraph ;
  1046. HANDLE hFile = 0 ;
  1047. LPTSTR pFileName = NULL ;
  1048. INT ErrCode = 0 ;
  1049. if (!(pGraph = pGraphs))
  1050. {
  1051. return ;
  1052. }
  1053. // see if there is anything to export..
  1054. if (!(pGraph->pLineFirst))
  1055. {
  1056. return ;
  1057. }
  1058. SetHourglassCursor() ;
  1059. if (ErrCode = ExportFileOpen (hWndGraph, &hFile, pGraph->gInterval, &pFileName))
  1060. {
  1061. goto Exit0 ;
  1062. }
  1063. if (!pFileName)
  1064. {
  1065. // this is the case when user cancel.
  1066. goto Exit0 ;
  1067. }
  1068. // export the column labels
  1069. if (!ExportChartLabels (hFile, pGraph))
  1070. {
  1071. ErrCode = ERR_EXPORT_FILE ;
  1072. goto Exit0 ;
  1073. }
  1074. // export the lines
  1075. if (PlayingBackLog())
  1076. {
  1077. if (!ExportLogChart (hFile, pGraph))
  1078. {
  1079. ErrCode = ERR_EXPORT_FILE ;
  1080. goto Exit0 ;
  1081. }
  1082. }
  1083. else
  1084. {
  1085. if (!ExportCurrentChart (hFile, pGraph))
  1086. {
  1087. ErrCode = ERR_EXPORT_FILE ;
  1088. goto Exit0 ;
  1089. }
  1090. }
  1091. Exit0:
  1092. SetArrowCursor() ;
  1093. if (hFile)
  1094. {
  1095. CloseHandle (hFile) ;
  1096. }
  1097. if (pFileName)
  1098. {
  1099. if (ErrCode)
  1100. {
  1101. DlgErrorBox (hWndGraph, ErrCode, pFileName) ;
  1102. }
  1103. MemoryFree (pFileName) ;
  1104. }
  1105. } // ExportChart
  1106. typedef struct CHARTDATAPOINTSTRUCT
  1107. {
  1108. int iLogIndex ;
  1109. int xDispDataPoint ;
  1110. } CHARTDATAPOINT, *PCHARTDATAPOINT ;
  1111. void PlaybackChartDataPoint (PCHARTDATAPOINT pChartDataPoint)
  1112. { // PlaybackChartDataPoint
  1113. int iDisplayTics ; // num visual points to display
  1114. int iDisplayTic ;
  1115. int iLogTic ;
  1116. int iLogTicsMove ;
  1117. BOOL bFirstTime = TRUE;
  1118. int iLogTicsRemaining ;
  1119. int numOfData, xDispDataPoint, rectWidth, xPos ;
  1120. PGRAPHSTRUCT pGraph ;
  1121. pGraph = GraphData (hWndGraph) ;
  1122. iLogTicsRemaining = PlaybackLog.iSelectedTics ;
  1123. // we only have iDisplayTics-1 points since
  1124. // we have to use the first two sample points to
  1125. // get the first data points.
  1126. if (iLogTicsRemaining <= pGraphs->gMaxValues)
  1127. {
  1128. iDisplayTics = iLogTicsRemaining ;
  1129. }
  1130. else
  1131. {
  1132. iDisplayTics = pGraphs->gMaxValues ;
  1133. }
  1134. iDisplayTic = -1 ;
  1135. iLogTic = PlaybackLog.StartIndexPos.iPosition ;
  1136. numOfData = pGraph->gMaxValues - 1 ;
  1137. rectWidth = pGraph->rectData.right - pGraph->rectData.left ;
  1138. xDispDataPoint = pGraph->rectData.left ;
  1139. while (iDisplayTics && numOfData)
  1140. {
  1141. if (!bFirstTime)
  1142. {
  1143. iDisplayTic++ ;
  1144. }
  1145. else
  1146. {
  1147. bFirstTime = FALSE ;
  1148. // get the second sample data to form the first data point
  1149. iLogTic++ ;
  1150. iLogTicsRemaining-- ;
  1151. iDisplayTic++ ;
  1152. }
  1153. pChartDataPoint[iDisplayTic].iLogIndex = iLogTic ;
  1154. pChartDataPoint[iDisplayTic].xDispDataPoint = xDispDataPoint ;
  1155. // setup DDA to get the index of the next sample point
  1156. iLogTicsMove = DDA_DISTRIBUTE (iLogTicsRemaining, iDisplayTics) ;
  1157. iLogTicsRemaining -= iLogTicsMove ;
  1158. iLogTic += iLogTicsMove ;
  1159. xPos = DDA_DISTRIBUTE (rectWidth, numOfData) ;
  1160. xDispDataPoint += xPos ;
  1161. numOfData-- ;
  1162. rectWidth -= xPos ;
  1163. iDisplayTics-- ;
  1164. } // while
  1165. } // PlaybackChartDataPoint