|
|
1.1 root 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:
16: //==========================================================================//
17: // Includes //
18: //==========================================================================//
19:
20: #include <stdio.h> // for sprintf
21:
22: #include "perfmon.h" // main perfmon declarations
23: #include "grafdata.h" // external declarations for this file
24: #include <float.h> // for FLT_MAX constant
25:
26: #include "addline.h" // for AddLine, EditLine
27: #include "counters.h" // for Counter_Counter, et al.
28: #include "graph.h" // for SizeGraphComponents
29: #include "pmemory.h" // for MemoryXXX (mallloc-type) routines
30: #include "perfdata.h" // for UpdateLines
31: #include "playback.h" // for PlayingBackLog, PlaybackLines
32: #include "legend.h"
33: #include "system.h" // for SystemGet
34: #include "utils.h"
35: #include "line.h" // for LineFree
36: #include "valuebar.h" // for StatusTimer
37:
38: #include "fileopen.h" // for FileGetName
39: #include "fileutil.h" // for FileRead...
40: #include "menuids.h" // for IDM_VIEWCHART
41: #include "perfmops.h" // for ExportFileHeader
42: #include "status.h" // for StatusLineReady
43:
44: extern BOOL SaveFileHandler(HWND hWnd,DWORD type) ;
45:
46: // this macro is used in doing a simple DDA (Digital Differential Analyzer)
47: // * 10 + 5 is to make the result round up with .5
48: #define DDA_DISTRIBUTE(TotalTics, numOfData) \
49: ((TotalTics * 10 / numOfData) + 5) / 10
50:
51: #define szSmallValueFormat TEXT("%10.3f")
52: #define szLargeValueFormat TEXT("%10.0f")
53:
54: //==========================================================================//
55: // Local Data //
56: //==========================================================================//
57:
58:
59:
60:
61: //==========================================================================//
62: // Local Functions //
63: //==========================================================================//
64:
65:
66: /****************************************************************************
67: * eUpdateMinMaxAve -
68: ****************************************************************************/
69: void eUpdateMinMaxAve (FLOAT eValue, PLINESTRUCT pLineStruct, INT iValidValues,
70: INT iTotalValidPoints, INT iDataPoint, INT gMaxPoints)
71: {
72: INT i ;
73: INT iDataNum = iTotalValidPoints ;
74: FLOAT eMin,
75: eMax,
76: eSum,
77: eNewValue ;
78:
79:
80: eMax = eMin = eValue ;
81:
82: if (PlayingBackLog())
83: {
84: eSum = (FLOAT) 0.0 ;
85: }
86: else
87: {
88: eSum = eValue ;
89: }
90:
91: if (iValidValues == iTotalValidPoints)
92: {
93: for (i=0 ; i < iValidValues ; i++)
94: {
95: if (i == iDataPoint)
96: {
97: // skip the data point we are going to replace
98: continue ;
99: }
100:
101: eNewValue = pLineStruct->lnValues[i] ;
102:
103: eSum += eNewValue ;
104:
105: if (eNewValue > eMax)
106: {
107: eMax = eNewValue ;
108: }
109:
110: if (eNewValue < eMin)
111: {
112: eMin = eNewValue ;
113: }
114: }
115: }
116: else
117: {
118: // special case when we start the new line in the middle of the chart
119: for (i = iDataPoint, iTotalValidPoints-- ;
120: iTotalValidPoints > 0 ;
121: iTotalValidPoints-- )
122: {
123: i-- ;
124: if (i < 0)
125: {
126: // for the wrap-around case..
127: i = gMaxPoints - 1 ;
128: }
129:
130: if (i == iDataPoint)
131: {
132: // skip the data point we are going to replace
133: continue ;
134: }
135: eNewValue = pLineStruct->lnValues[i] ;
136:
137: eSum += eNewValue ;
138:
139: if (eNewValue > eMax)
140: {
141: eMax = eNewValue ;
142: }
143:
144: if (eNewValue < eMin)
145: {
146: eMin = eNewValue ;
147: }
148: }
149: }
150:
151: pLineStruct->lnMinValue = eMin ;
152: pLineStruct->lnMaxValue = eMax ;
153:
154: if (iDataNum)
155: {
156: pLineStruct->lnAveValue = eSum / (FLOAT) iDataNum ;
157: }
158: else
159: {
160: pLineStruct->lnAveValue = (FLOAT) 0.0 ;
161: }
162: }
163:
164:
165: // UpdateValueBarData is used to update the value bar data
166: // It is called when the user switches to a diff. line from
167: // the legned window.
168: VOID UpdateValueBarData (PGRAPHSTRUCT pGraph)
169: {
170: PLINESTRUCT pCurrentGraphLine ;
171: INT KnownValue,
172: MaxValues,
173: iValidValues,
174: iDataPoint ;
175: FLOAT eValue ;
176: pCurrentGraphLine = CurrentGraphLine (hWndGraph) ;
177:
178: if (!pCurrentGraphLine || pCurrentGraphLine->bFirstTime)
179: {
180: // we have not collect enough samples
181: return ;
182: }
183:
184: KnownValue = pGraph->gKnownValue ;
185: MaxValues = pGraph->gMaxValues ;
186:
187: // The valid values is the number of valid entries in the
188: // data buffer. After we wrap the buffer, all the values are
189: // valid.
190: iValidValues = pGraph->gTimeLine.iValidValues ;
191:
192: // Get the index to the data point we are updating.
193:
194: iDataPoint = KnownValue % MaxValues ;
195: eValue = pCurrentGraphLine->lnValues[iDataPoint] ;
196:
197: // get the statistical data for this line
198: eUpdateMinMaxAve(eValue, pCurrentGraphLine,
199: iValidValues, pCurrentGraphLine->lnValidValues,
200: iDataPoint, MaxValues) ;
201: } // UpdateValueBarData
202:
203:
204: VOID UpdateLGData (PGRAPHSTRUCT pGraph)
205: {
206: PLINESTRUCT pLine ;
207: PLINESTRUCT pCurrentGraphLine ;
208: INT KnownValue,
209: MaxValues,
210: iValidValues,
211: iDataPoint ;
212: FLOAT eValue ;
213: // Known Value is the where data is placed in the buffer.
214: pGraph->gKnownValue++;
215:
216: KnownValue = pGraph->gKnownValue ;
217:
218: // Update the high water mark for valid data in the lnValues
219: // (aka DataPoint) buffer.
220:
221:
222: MaxValues = pGraph->gMaxValues ;
223:
224: // The valid values is the number of valid entries in the
225: // data buffer. After we wrap the buffer, all the values are
226: // valid.
227: iValidValues = pGraph->gTimeLine.iValidValues ;
228:
229: if (iValidValues < MaxValues)
230: iValidValues = (KnownValue % MaxValues) + 1 ;
231:
232: pGraph->gTimeLine.iValidValues = iValidValues ;
233:
234: // Get the index to the data point we are updating.
235:
236: iDataPoint = KnownValue % MaxValues ;
237:
238: // loop through lines,
239: // If one of the lines is highlighted then do the calculations
240: // for average, min, & max on that line.
241:
242: pCurrentGraphLine = CurrentGraphLine (hWndGraph) ;
243:
244: for (pLine=pGraph->pLineFirst; pLine; pLine=pLine->pLineNext)
245: { // for
246:
247: if (pLine->bFirstTime)
248: {
249: // skip until we have collect enough samples to plot the first data
250: continue ;
251: }
252:
253: if (pLine->lnValidValues < MaxValues)
254: {
255: (pLine->lnValidValues)++ ;
256: }
257:
258: // Get the new value for this line.
259: eValue = (*(pLine->valNext))(pLine) ;
260:
261: if (pLine == pCurrentGraphLine)
262: { // if
263: // get the statistical data for this line
264: eUpdateMinMaxAve (eValue, pLine,
265: iValidValues, pLine->lnValidValues,
266: iDataPoint, MaxValues) ;
267: } // if
268:
269: // Now put the new value into the data array
270: pLine->lnValues[iDataPoint] = eValue ;
271: }
272:
273: GetLocalTime (&(pGraph->pDataTime[iDataPoint])) ;
274: } // UpdateLGData
275:
276:
277:
278: BOOL HandleGraphTimer (void)
279: {
280: PGRAPHSTRUCT pGraph;
281:
282: //NOTE: get a strategy for these "no-go" states
283: if (!(pGraph = pGraphs) || !pGraphs->pSystemFirst)
284: return(FALSE);
285:
286:
287: if (!UpdateLines(&(pGraphs->pSystemFirst), pGraphs->pLineFirst))
288: return (TRUE) ;
289:
290: UpdateLGData(pGraph);
291:
292: return(TRUE);
293: }
294:
295:
296: VOID ClearGraphTimer(PGRAPHSTRUCT pGraph)
297: {
298: KillTimer(pGraph->hWnd, GRAPH_TIMER_ID);
299: }
300:
301:
302: VOID SetGraphTimer(PGRAPHSTRUCT pGraph)
303: {
304: SetTimer(pGraph->hWnd, GRAPH_TIMER_ID, pGraph->gInterval, NULL) ;
305: }
306:
307: VOID ResetGraphTimer(PGRAPHSTRUCT pGraph)
308: {
309: KillTimer(pGraph->hWnd, GRAPH_TIMER_ID);
310: SetGraphTimer(pGraph);
311: }
312:
313:
314: VOID GetGraphConfig(PGRAPHSTRUCT pGraph)
315: {
316:
317: LoadRefreshSettings(pGraph);
318: LoadLineGraphSettings(pGraph);
319:
320:
321: // Init the structure
322: pGraph->pLineFirst = NULL;
323:
324: //NOTE: put the rest of this in Config
325:
326: pGraph->gOptions.bLegendChecked = TRUE;
327: pGraph->gOptions.bMenuChecked = TRUE;
328: pGraph->gOptions.bLabelsChecked = TRUE;
329: pGraph->gOptions.bVertGridChecked = FALSE;
330: pGraph->gOptions.bHorzGridChecked = FALSE;
331: pGraph->gOptions.bStatusBarChecked = TRUE;
332: pGraph->gOptions.GraphVGrid = TRUE;
333: pGraph->gOptions.GraphHGrid = TRUE;
334: pGraph->gOptions.HistVGrid = TRUE;
335: pGraph->gOptions.HistHGrid = TRUE;
336:
337: pGraph->gOptions.iGraphOrHistogram = LINE_GRAPH; // vs. BAR_GRAPH
338: pGraph->gOptions.iVertMax = DEF_GRAPH_VMAX;
339:
340: return;
341: }
342:
343:
344: BOOL InsertGraph (HWND hWnd)
345: {
346: PGRAPHSTRUCT pGraph;
347:
348: pGraph = MemoryAllocate (sizeof (GRAPHSTRUCT)) ;
349: if (!pGraph)
350: return (FALSE) ;
351:
352:
353: pGraphs = pGraph;
354:
355:
356: GetGraphConfig(pGraph);
357: pGraph->bManualRefresh = FALSE ;
358:
359: pGraph->gMaxValues = DEFAULT_MAX_VALUES;
360: pGraph->pptDataPoints =
361: (PPOINT) MemoryAllocate (sizeof (POINT) * pGraph->gMaxValues) ;
362:
363: pGraph->pDataTime =
364: (SYSTEMTIME *) MemoryAllocate (sizeof(SYSTEMTIME) * pGraph->gMaxValues) ;
365:
366: pGraph->hWnd = hWnd ;
367: pGraph->bModified = FALSE ;
368:
369: pGraph->Visual.iColorIndex = 0 ;
370: pGraph->Visual.iWidthIndex = 0 ;
371: pGraph->Visual.iStyleIndex = 0 ;
372:
373: return(TRUE) ;
374: }
375:
376:
377:
378: void PlaybackSetGraphLines (HWND hWndChart,
379: PLINE pLineFirst,
380: int iDisplayTic,
381: int iLogTic,
382: BOOL CalcData)
383: {
384: PLINE pLine ;
385: FLOAT eValue ;
386:
387: for (pLine = pLineFirst ;
388: pLine ;
389: pLine = pLine->pLineNext)
390: { // for
391: eValue = (*(pLine->valNext))(pLine) ;
392: pLine->lnValues[iDisplayTic] = eValue ;
393: pLine->aiLogIndexes[iDisplayTic] = iLogTic ;
394:
395: // only need to do this on request.
396: if (CalcData)
397: {
398: eUpdateMinMaxAve (eValue, pLine, iDisplayTic, iDisplayTic,
399: iDisplayTic, iDisplayTic) ;
400: } // if
401: } // for
402: } // PlaybackSetGraphLines
403:
404:
405:
406: BOOL ChartInsertLine (PGRAPHSTRUCT pGraph,
407: PLINE pLine)
408: /*
409: Effect: Insert the line pLine into the graph pGraph and
410: allocate space for the graph's number of values.
411:
412: Returns: Whether the line could be added and space allocated.
413:
414: See Also: LineAllocate (line.c), ChartDeleteLine.
415: */
416: { // ChartInsertLine
417: PLINE pLineEquivalent ;
418: INT i ;
419: FLOAT *pTempPts;
420: HPEN tempPen ;
421:
422: pGraph->bModified = TRUE ;
423:
424: pLineEquivalent = FindEquivalentLine (pLine, pGraph->pLineFirst) ;
425: if (pLineEquivalent)
426: {
427: pLineEquivalent->Visual = pLine->Visual ;
428: pLineEquivalent->iScaleIndex = pLine->iScaleIndex ;
429: pLineEquivalent->eScale = pLine->eScale ;
430:
431: tempPen = pLineEquivalent->hPen ;
432: pLineEquivalent->hPen = pLine->hPen ;
433: pLine->hPen = tempPen ;
434: return FALSE ;
435: }
436: else
437: {
438: if (!pGraph->pLineFirst && !PlayingBackLog())
439: {
440: SetGraphTimer (pGraph) ;
441: }
442:
443: if (!SystemAdd (&pGraph->pSystemFirst, pLine->lnSystemName))
444: return FALSE;
445:
446: LineAppend (&pGraph->pLineFirst, pLine) ;
447:
448: pLine->lnMinValue = FLT_MAX ;
449: pLine->lnMaxValue = - FLT_MAX ;
450: pLine->lnAveValue = 0.0F ;
451: pLine->lnValidValues = 0 ;
452:
453: pLine->lnValues =
454: (FLOAT *) MemoryAllocate (sizeof (FLOAT) * pGraph->gMaxValues) ;
455:
456: for (i = pGraph->gMaxValues, pTempPts = pLine->lnValues ;
457: i > 0 ;
458: i-- )
459: {
460: *pTempPts++ = (FLOAT) 0.0 ;
461: }
462:
463: if (PlayingBackLog ())
464: {
465: pLine->aiLogIndexes =
466: (int *) MemoryAllocate (sizeof (LONG) * pGraph->gMaxValues) ;
467: }
468:
469: // Add the line to the legend, resize the legend window, and then
470: // select the new line as the current legend item. Do it in this
471: // sequence to avoid the legend scroll bar momentarily appearing and
472: // then disappearing, since the resize will obviate the scroll bar.
473:
474: LegendAddItem (hWndGraphLegend, pLine) ;
475:
476: if (!bDelayAddAction)
477: {
478: SizeGraphComponents (hWndGraph) ;
479: LegendSetSelection (hWndGraphLegend,
480: LegendNumItems (hWndGraphLegend) - 1) ;
481:
482: if (PlayingBackLog ())
483: PlaybackChart (pGraph->hWnd) ;
484: }
485: }
486:
487: return (TRUE) ;
488: } // ChartInsertLine
489:
490:
491: VOID ChartDeleteLine (PGRAPHSTRUCT pGraph,
492: PLINESTRUCT pLine)
493: {
494: PLINESTRUCT npLine;
495:
496:
497: pGraph->bModified = TRUE ;
498:
499: if (pGraph->pLineFirst == pLine)
500: pGraph->pLineFirst = pLine->pLineNext;
501: else
502: {
503: for (npLine = pGraph->pLineFirst; npLine; npLine = npLine->pLineNext)
504: {
505: if (npLine->pLineNext == pLine)
506: npLine->pLineNext = pLine->pLineNext;
507: }
508: }
509:
510: if (!pGraph->pLineFirst)
511: {
512: ResetGraph (pGraph) ;
513: }
514: else
515: {
516: BuildNewValueListForGraph () ;
517: }
518:
519: // Delete the legend entry for this line.
520: // If the line was highlighted then this will undo the highlight.
521:
522: LegendDeleteItem (hWndGraphLegend, pLine) ;
523:
524: LineFree (pLine) ;
525:
526: SizeGraphComponents (hWndGraph) ;
527:
528:
529: }
530:
531:
532: FLOAT Counter_Queuelen(PLINESTRUCT pLine)
533: {
534:
535: return((FLOAT)0.0);
536: // pLine;
537: }
538:
539:
540: void ClearGraphDisplay (PGRAPHSTRUCT pGraph)
541: {
542: PLINESTRUCT pLine;
543:
544: // reset the timeline data
545: pGraph->gKnownValue = -1 ;
546: pGraph->gTimeLine.iValidValues = 0 ;
547: pGraph->gTimeLine.xLastTime = 0 ;
548: memset (pGraph->pDataTime, 0, sizeof(SYSTEMTIME) * pGraph->gMaxValues) ;
549:
550: // loop through lines,
551: // If one of the lines is highlighted then do the calculations
552: // for average, min, & max on that line.
553:
554: for (pLine=pGraph->pLineFirst; pLine; pLine=pLine->pLineNext)
555: { // for
556:
557: pLine->bFirstTime = 2 ;
558: pLine->lnMinValue = FLT_MAX ;
559: pLine->lnMaxValue = - FLT_MAX ;
560: pLine->lnAveValue = 0.0F ;
561: pLine->lnValidValues = 0 ;
562: memset (pLine->lnValues, 0, sizeof(FLOAT) * pGraph->gMaxValues) ;
563: }
564:
565: StatusTimer (hWndGraphStatus, TRUE) ;
566: WindowInvalidate (hWndGraphDisplay) ;
567: }
568:
569: void ResetGraphView (HWND hWndGraph)
570: {
571: PGRAPHSTRUCT pGraph ;
572:
573: pGraph = GraphData (hWndGraph) ;
574:
575:
576: if (!pGraph)
577: {
578: return ;
579: }
580:
581: ChangeSaveFileName (NULL, IDM_VIEWCHART) ;
582:
583: if (pGraph->pSystemFirst)
584: {
585: ResetGraph (pGraph) ;
586: }
587: } // ResetGraphView
588:
589: void ResetGraph (PGRAPHSTRUCT pGraph)
590: {
591: ClearGraphTimer (pGraph) ;
592: ClearLegend (hWndGraphLegend) ;
593: if (pGraph->pLineFirst)
594: {
595: FreeLines (pGraph->pLineFirst) ;
596: pGraph->pLineFirst = NULL ;
597: }
598:
599: if (pGraph->pSystemFirst)
600: {
601: FreeSystems (pGraph->pSystemFirst) ;
602: pGraph->pSystemFirst = NULL ;
603: }
604:
605: pGraph->gKnownValue = -1 ;
606: pGraph->gTimeLine.iValidValues = 0 ;
607: pGraph->gTimeLine.xLastTime = 0 ;
608:
609: // reset visual data
610: pGraph->Visual.iColorIndex = 0 ;
611: pGraph->Visual.iWidthIndex = 0 ;
612: pGraph->Visual.iStyleIndex = 0 ;
613:
614: memset (pGraph->pDataTime, 0, sizeof(SYSTEMTIME) * pGraph->gMaxValues) ;
615:
616: SizeGraphComponents (hWndGraph) ;
617: InvalidateRect(hWndGraph, NULL, TRUE) ;
618: }
619:
620:
621:
622: void PlaybackChart (HWND hWndChart)
623: { // PlaybackChart
624: int iDisplayTics ; // num visual points to display
625: int iDisplayTic ;
626: int iLogTic ;
627: int iLogTicsMove ;
628: BOOL bFirstTime = TRUE;
629: int iLogTicsRemaining ;
630:
631: if (!pGraphs->pLineFirst)
632: {
633: // no line to playback
634: return ;
635: }
636:
637: iLogTicsRemaining = PlaybackLog.iSelectedTics ;
638:
639:
640: // we only have iDisplayTics-1 points since
641: // we have to use the first two sample points to
642: // get the first data points.
643: if (iLogTicsRemaining <= pGraphs->gMaxValues)
644: {
645: iDisplayTics = iLogTicsRemaining ;
646: pGraphs->gTimeLine.iValidValues = iDisplayTics - 1 ;
647: }
648: else
649: {
650: iDisplayTics = pGraphs->gMaxValues ;
651: pGraphs->gTimeLine.iValidValues = iDisplayTics ;
652: }
653:
654: iDisplayTic = -1 ;
655: iLogTic = PlaybackLog.StartIndexPos.iPosition ;
656:
657: while (iDisplayTics)
658: {
659:
660: PlaybackLines (pGraphs->pSystemFirst,
661: pGraphs->pLineFirst,
662: iLogTic) ;
663:
664: if (bFirstTime)
665: {
666: bFirstTime = FALSE ;
667:
668: // get the second sample data to form the first data point
669: iLogTic++ ;
670: iLogTicsRemaining-- ;
671: PlaybackLines (pGraphs->pSystemFirst,
672: pGraphs->pLineFirst,
673: iLogTic) ;
674: }
675: iDisplayTic++ ;
676: PlaybackSetGraphLines (hWndChart, pGraphs->pLineFirst,
677: iDisplayTic, iLogTic, (iDisplayTics == 1)) ;
678:
679: // setup DDA to get the index of the next sample point
680: iLogTicsMove = DDA_DISTRIBUTE (iLogTicsRemaining, iDisplayTics) ;
681: iLogTicsRemaining -= iLogTicsMove ;
682: iLogTic += iLogTicsMove ;
683:
684: iDisplayTics-- ;
685:
686: } // while
687:
688: // point to the last value for valuebar display
689: pGraphs->gKnownValue = iDisplayTic ;
690:
691: } // PlaybackChart
692:
693:
694:
695: #if 0
696: PLINESTRUCT CurrentGraphLine (HWND hWndGraph)
697: { // CurrentGraphLine
698: UNREFERENCED_PARAMETER (hWndGraph) ;
699:
700: return (LegendCurrentLine (hWndGraphLegend)) ;
701: }
702: #endif
703:
704:
705: BOOL AddChart (HWND hWndParent)
706: {
707: return (AddLine (hWndParent,
708: &(pGraphs->pSystemFirst),
709: &(pGraphs->Visual),
710: LineTypeChart)) ;
711: }
712:
713:
714: BOOL EditChart (HWND hWndParent)
715: { // EditChart
716: return (EditLine (hWndParent,
717: &(pGraphs->pSystemFirst),
718: CurrentGraphLine (hWndGraph),
719: LineTypeChart)) ;
720: }
721:
722:
723: BOOL QuerySaveChart (HWND hWndParent, PGRAPHSTRUCT pGraph)
724: /*
725: Effect: If the graph pGraph is modified, put up a message
726: box allowing the user to save the current graph.
727:
728: Return whether the caller should proceed to load in
729: a new or otherwise trash the current graph.
730: */
731: { // QuerySaveChart
732: #ifdef KEEP_QUERY
733: int iReturn ;
734:
735: if (!pGraph->bModified)
736: return (TRUE) ;
737:
738: iReturn = MessageBoxResource (hWndParent,
739: IDS_SAVECHART, IDS_MODIFIEDCHART,
740: MB_YESNOCANCEL | MB_ICONASTERISK) ;
741:
742: if (iReturn == IDCANCEL)
743: return (FALSE) ;
744:
745: if (iReturn == IDYES)
746: SaveChart (hWndGraphs, 0, 0) ;
747: return (TRUE) ;
748: #endif
749: return (TRUE) ; // we don't want to query nor save change
750:
751: } // QuerySaveChart
752:
753: void GraphAddAction ()
754: {
755: PGRAPHSTRUCT pGraph ;
756:
757: pGraph = GraphData (hWndGraph) ;
758:
759: SizeGraphComponents (hWndGraph) ;
760:
761: LegendSetSelection (hWndGraphLegend,
762: LegendNumItems (hWndGraphLegend) - 1) ;
763:
764: if (PlayingBackLog ())
765: PlaybackChart (pGraph->hWnd) ;
766: }
767:
768: BOOL OpenChartVer1 (HANDLE hFile,
769: DISKCHART *pDiskChart,
770: PGRAPHSTRUCT pGraph)
771: { // OpenChartVer1
772: bDelayAddAction = TRUE ;
773: pGraph->Visual = pDiskChart->Visual ;
774: pGraph->gOptions = pDiskChart->gOptions ;
775: pGraph->gMaxValues = pDiskChart->gMaxValues ;
776: pGraph->bManualRefresh = pDiskChart->bManualRefresh ;
777: pGraphs->gInterval = (INT) (pGraph->gOptions.eTimeInterval * (FLOAT) 1000.0) ;
778: ReadLines (hFile, pDiskChart->dwNumLines,
779: &(pGraph->pSystemFirst), &(pGraph->pLineFirst), IDM_VIEWCHART) ;
780:
781: bDelayAddAction = FALSE ;
782:
783: GraphAddAction () ;
784:
785: return (TRUE) ;
786: } // OpenChartVer1
787:
788:
789:
790: BOOL OpenChart (HWND hWndGraph,
791: HANDLE hFile,
792: DWORD dwMajorVersion,
793: DWORD dwMinorVersion,
794: BOOL bChartFile)
795: { // OpenChart
796: PGRAPHSTRUCT pGraph ;
797: DISKCHART DiskChart ;
798: BOOL bSuccess = TRUE ;
799:
800: pGraph = pGraphs ;
801: if (!pGraph)
802: {
803: bSuccess = FALSE ;
804: goto Exit0 ;
805: }
806:
807: if (!FileRead (hFile, &DiskChart, sizeof (DISKCHART)))
808: {
809: bSuccess = FALSE ;
810: goto Exit0 ;
811: }
812:
813:
814: switch (dwMajorVersion)
815: {
816: case (1):
817:
818: SetHourglassCursor() ;
819:
820: ResetGraphView (hWndGraph) ;
821:
822: OpenChartVer1 (hFile, &DiskChart, pGraph) ;
823:
824: // change to chart view if we are opening a
825: // chart file
826: if (bChartFile && iPerfmonView != IDM_VIEWCHART)
827: {
828: SendMessage (hWndMain, WM_COMMAND, (LONG)IDM_VIEWCHART, 0L) ;
829: }
830:
831: if (iPerfmonView == IDM_VIEWCHART)
832: {
833: SetPerfmonOptions (&DiskChart.perfmonOptions) ;
834: }
835:
836: SetArrowCursor() ;
837:
838: break ;
839: } // switch
840:
841: Exit0:
842:
843: if (bChartFile)
844: {
845: CloseHandle (hFile) ;
846: }
847:
848: return (bSuccess) ;
849: } // OpenChart
850:
851: BOOL SaveChart (HWND hWndGraph, HANDLE hInputFile, BOOL bGetFileName)
852: {
853: PGRAPHSTRUCT pGraph ;
854: PLINE pLine ;
855: HANDLE hFile ;
856: DISKCHART DiskChart ;
857: PERFFILEHEADER FileHeader ;
858: TCHAR szFileName [256] ;
859: BOOL newFileName = FALSE ;
860:
861: if (hInputFile)
862: {
863: // use the input file handle if it is available
864: // this is the case for saving workspace data
865: hFile = hInputFile ;
866: }
867: else
868: {
869: if (pChartFullFileName)
870: {
871: lstrcpy (szFileName, pChartFullFileName) ;
872: }
873: if (bGetFileName || pChartFullFileName == NULL)
874: {
875: // if (!pChartFullFileName)
876: // {
877: // StringLoad (IDS_GRAPH_FNAME, szFileName) ;
878: // }
879:
880: if (!FileGetName (hWndGraph, IDS_CHARTFILE, szFileName))
881: {
882: return (FALSE) ;
883: }
884: newFileName = TRUE ;
885: }
886:
887: hFile = FileHandleCreate (szFileName) ;
888:
889: if (hFile && newFileName)
890: {
891: ChangeSaveFileName (szFileName, IDM_VIEWCHART) ;
892: }
893: else if (!hFile)
894: {
895: DlgErrorBox (hWndGraph, ERR_CANT_OPEN, szFileName) ;
896: }
897: }
898:
899: if (!hFile)
900: return (FALSE) ;
901:
902: pGraph = pGraphs ;
903: if (!pGraph)
904: {
905: if (!hInputFile)
906: {
907: CloseHandle (hFile) ;
908: }
909: return (FALSE) ;
910: }
911:
912: if (!hInputFile)
913: {
914: // only need to write file header if not workspace
915: memset (&FileHeader, 0, sizeof (FileHeader)) ;
916: lstrcpy (FileHeader.szSignature, szPerfChartSignature) ;
917: FileHeader.dwMajorVersion = ChartMajorVersion ;
918: FileHeader.dwMinorVersion = ChartMinorVersion ;
919:
920: if (!FileWrite (hFile, &FileHeader, sizeof (PERFFILEHEADER)))
921: {
922: goto Exit0 ;
923: }
924: }
925:
926: DiskChart.Visual = pGraph->Visual ;
927: DiskChart.gOptions = pGraph->gOptions ;
928: DiskChart.gMaxValues = pGraph->gMaxValues ;
929: DiskChart.dwNumLines = NumLines (pGraph->pLineFirst) ;
930: DiskChart.bManualRefresh = pGraph->bManualRefresh ;
931: DiskChart.perfmonOptions = Options ;
932:
933: if (!FileWrite (hFile, &DiskChart, sizeof (DISKCHART)))
934: {
935: goto Exit0 ;
936: }
937:
938: for (pLine = pGraph->pLineFirst ;
939: pLine ;
940: pLine = pLine->pLineNext)
941: { // for
942: if (!WriteLine (pLine, hFile))
943: {
944: goto Exit0 ;
945: }
946: } // for
947:
948: if (!hInputFile)
949: {
950: CloseHandle (hFile) ;
951: }
952:
953: return (TRUE) ;
954:
955: Exit0:
956: if (!hInputFile)
957: {
958: CloseHandle (hFile) ;
959:
960: // only need to report error if not workspace
961: DlgErrorBox (hWndGraph, ERR_SETTING_FILE, szFileName) ;
962: }
963: return (FALSE) ;
964:
965: } // SaveChart
966:
967: #define TIME_TO_WRITE 6
968: BOOL ExportChartLabels (HANDLE hFile, PGRAPHSTRUCT pGraph)
969: {
970: TCHAR UnicodeBuff [MiscTextLen] ;
971: CHAR TempBuff [LongTextLen] ;
972: int StringLen ;
973: PLINESTRUCT pLine;
974: int TimeToWriteFile ;
975: int iIndex ;
976: LPTSTR lpItem ;
977:
978: for (iIndex = 0 ; iIndex < 5 ; iIndex++)
979: {
980: // for iIndex == 0, get counter name
981: // for iIndex == 1, get instance name
982: // for iIndex == 2, get parent name
983: // for iIndex == 3, get object name
984: // for iIndex == 4, get computer name
985: if (iIndex == 4)
986: {
987: // the last label field, write date/time labels
988: strcpy (TempBuff, LineEndStr) ;
989: StringLen = strlen (TempBuff) ;
990: StringLoad (IDS_EXPORT_DATE, UnicodeBuff) ;
991: ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
992: strcat (TempBuff, pDelimiter) ;
993: StringLen = strlen (TempBuff) ;
994:
995: StringLoad (IDS_EXPORT_TIME, UnicodeBuff) ;
996: ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
997: strcat (TempBuff, pDelimiter) ;
998: StringLen = strlen (TempBuff) ;
999: }
1000: else
1001: {
1002: strcpy (TempBuff, LineEndStr) ;
1003: strcat (TempBuff, pDelimiter) ;
1004: strcat (TempBuff, pDelimiter) ;
1005: StringLen = strlen (TempBuff) ;
1006: }
1007:
1008: TimeToWriteFile = 0 ;
1009:
1010: for (pLine=pGraph->pLineFirst; pLine; pLine=pLine->pLineNext)
1011: {
1012: switch (iIndex)
1013: {
1014: case 0:
1015: lpItem = (LPTSTR) pLine->lnCounterName ;
1016: break ;
1017:
1018: case 1:
1019: lpItem = (LPTSTR) pLine->lnInstanceName ;
1020: break ;
1021:
1022: case 2:
1023: lpItem = (LPTSTR) pLine->lnPINName ;
1024: break ;
1025:
1026: case 3:
1027: lpItem = (LPTSTR) pLine->lnObjectName ;
1028: break ;
1029:
1030: case 4:
1031: lpItem = (LPTSTR) pLine->lnSystemName ;
1032: break ;
1033: }
1034:
1035: if (lpItem)
1036: {
1037: ConvertUnicodeStr (&TempBuff[StringLen], lpItem) ;
1038: }
1039: else
1040: {
1041: TempBuff[StringLen] = '\0' ;
1042: }
1043: strcat (TempBuff, pDelimiter);
1044: StringLen = strlen (TempBuff) ;
1045:
1046: if (++TimeToWriteFile > TIME_TO_WRITE)
1047: {
1048: // better write the buffers before they overflow.
1049: // there are better ways to check for overflow
1050: // but this is good enough
1051:
1052: if (!FileWrite (hFile, TempBuff, StringLen))
1053: {
1054: goto Exit0 ;
1055: }
1056: StringLen = TimeToWriteFile = 0 ;
1057: }
1058: } // for each line
1059:
1060: if (StringLen)
1061: {
1062: // write the last block of data
1063: if (!FileWrite (hFile, TempBuff, StringLen))
1064: {
1065: goto Exit0 ;
1066: }
1067: }
1068: } // for iIndex
1069:
1070: return (TRUE) ;
1071:
1072: Exit0:
1073: return (FALSE) ;
1074:
1075: } // ExportChartLabels
1076:
1077: BOOL ExportLogChart (HANDLE hFile, PGRAPHSTRUCT pGraph)
1078: {
1079: TCHAR UnicodeBuff [MiscTextLen] ;
1080: CHAR TempBuff [LongTextLen] ;
1081: int StringLen ;
1082: PLINESTRUCT pLine;
1083: int TimeToWriteFile ;
1084: FLOAT eValue ;
1085: int iLogTic ;
1086: BOOL bFirstTime = TRUE ;
1087: SYSTEMTIME LogSystemTime ;
1088: LOGPOSITION LogPosition ;
1089:
1090: iLogTic = PlaybackLog.StartIndexPos.iPosition ;
1091:
1092: // we have to export every point from the log file
1093:
1094: for ( ; iLogTic <= PlaybackLog.StopIndexPos.iPosition ; iLogTic++)
1095: {
1096:
1097: PlaybackLines (pGraphs->pSystemFirst,
1098: pGraphs->pLineFirst,
1099: iLogTic) ;
1100:
1101: if (!bFirstTime)
1102: {
1103: // export the values
1104: TimeToWriteFile = 0 ;
1105:
1106:
1107: if (!LogPositionN (iLogTic, &LogPosition))
1108: {
1109: goto Exit0 ;
1110: }
1111:
1112: LogPositionSystemTime (&LogPosition, &LogSystemTime) ;
1113:
1114: strcpy (TempBuff, LineEndStr) ;
1115: StringLen = strlen (TempBuff) ;
1116:
1117: SystemTimeDateString (&LogSystemTime, UnicodeBuff) ;
1118: ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
1119: strcat (TempBuff, pDelimiter) ;
1120: StringLen = strlen (TempBuff) ;
1121:
1122: SystemTimeTimeString (&LogSystemTime, UnicodeBuff) ;
1123: ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
1124: strcat (TempBuff, pDelimiter) ;
1125: StringLen = strlen (TempBuff) ;
1126:
1127: for (pLine=pGraph->pLineFirst; pLine; pLine=pLine->pLineNext)
1128: {
1129:
1130: eValue = (*(pLine->valNext))(pLine) ;
1131:
1132: TSPRINTF (UnicodeBuff,
1133: eValue > (FLOAT)999999.0 ?
1134: szLargeValueFormat : szSmallValueFormat,
1135: eValue) ;
1136: ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
1137: strcat (TempBuff, pDelimiter) ;
1138: StringLen = strlen (TempBuff) ;
1139:
1140: if (++TimeToWriteFile > TIME_TO_WRITE)
1141: {
1142: if (!FileWrite (hFile, TempBuff, StringLen))
1143: {
1144: goto Exit0 ;
1145: }
1146: StringLen = TimeToWriteFile = 0 ;
1147: TempBuff[0] = '\0' ;
1148: }
1149: }
1150:
1151: if (StringLen)
1152: {
1153: if (!FileWrite (hFile, TempBuff, StringLen))
1154: {
1155: goto Exit0 ;
1156: }
1157: }
1158: }
1159: else
1160: {
1161: // skip the first data point since we
1162: // need 2 points to form the first value
1163: bFirstTime = FALSE ;
1164: }
1165: }
1166:
1167: return (TRUE) ;
1168:
1169: Exit0:
1170: return (FALSE) ;
1171:
1172: } // ExportLogChart
1173:
1174: BOOL ExportLineValue (HANDLE hFile, PGRAPHSTRUCT pGraph,
1175: int CurrentIndex, int iDataPoint)
1176: {
1177: TCHAR UnicodeBuff [MiscTextLen] ;
1178: CHAR TempBuff [LongTextLen] ;
1179: int StringLen ;
1180: PLINESTRUCT pLine;
1181: int MaxValues ;
1182: int TimeToWriteFile ;
1183: SYSTEMTIME *pSystemTime ;
1184: BOOL ValidValue ;
1185:
1186: pSystemTime = pGraph->pDataTime ;
1187: pSystemTime += CurrentIndex ;
1188:
1189: if (pSystemTime->wYear == 0 && pSystemTime->wYear == 0)
1190: {
1191: // ignore value that has 0 system time
1192: return (TRUE) ;
1193: }
1194:
1195: MaxValues = pGraph->gMaxValues ;
1196: strcpy (TempBuff, LineEndStr) ;
1197: StringLen = strlen (TempBuff) ;
1198:
1199: SystemTimeDateString (pSystemTime, UnicodeBuff) ;
1200: ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
1201: strcat (TempBuff, pDelimiter) ;
1202: StringLen = strlen (TempBuff) ;
1203:
1204: SystemTimeTimeString (pSystemTime, UnicodeBuff) ;
1205: ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
1206: strcat (TempBuff, pDelimiter) ;
1207: StringLen = strlen (TempBuff) ;
1208:
1209: TimeToWriteFile = 0 ;
1210: for (pLine=pGraph->pLineFirst; pLine; pLine=pLine->pLineNext)
1211: {
1212: if (!pLine->bFirstTime)
1213: {
1214: ValidValue = FALSE ;
1215: // check if this is a valid value
1216: if (pLine->lnValidValues == MaxValues)
1217: {
1218: // this is the simple case where we have filled up
1219: // the whole buffer
1220: ValidValue = TRUE ;
1221: }
1222: else if (pLine->lnValidValues <= iDataPoint)
1223: {
1224: if (CurrentIndex <= iDataPoint &&
1225: CurrentIndex > iDataPoint - pLine->lnValidValues)
1226: {
1227: ValidValue = TRUE ;
1228: }
1229: }
1230: else
1231: {
1232: if (CurrentIndex <= iDataPoint ||
1233: CurrentIndex > (MaxValues - pLine->lnValidValues + iDataPoint))
1234: {
1235: // this is the case when we start the new line in the middle
1236: // and data buffer has been wrap-around.
1237: ValidValue = TRUE ;
1238: }
1239: }
1240:
1241: // only export the data when we determine it is valid
1242: if (ValidValue)
1243: {
1244: TSPRINTF (UnicodeBuff,
1245: pLine->lnValues[CurrentIndex] > (FLOAT)999999.0 ?
1246: szLargeValueFormat : szSmallValueFormat,
1247: pLine->lnValues[CurrentIndex]) ;
1248: ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
1249: }
1250: }
1251: strcat (TempBuff, pDelimiter) ;
1252: StringLen = strlen (TempBuff) ;
1253:
1254: if (++TimeToWriteFile > TIME_TO_WRITE)
1255: {
1256: // better write the buffers before they overflow.
1257: // there are better ways to check for overflow
1258: // but this is good enough
1259:
1260: if (!FileWrite (hFile, TempBuff, StringLen))
1261: {
1262: goto Exit0 ;
1263: }
1264: StringLen = TimeToWriteFile = 0 ;
1265: TempBuff[0] = '\0' ;
1266: }
1267: }
1268:
1269: if (StringLen)
1270: {
1271: // write the last block of data
1272: if (!FileWrite (hFile, TempBuff, StringLen))
1273: {
1274: goto Exit0 ;
1275: }
1276: }
1277:
1278: return (TRUE) ;
1279:
1280: Exit0:
1281: return (FALSE) ;
1282:
1283: } // ExportLineValue
1284:
1285: BOOL ExportCurrentChart (HANDLE hFile, PGRAPHSTRUCT pGraph)
1286: {
1287: int KnownValue,
1288: MaxValues,
1289: iValidValues,
1290: iDataPoint ;
1291: BOOL SimpleCase = FALSE ;
1292: int iIndex ;
1293:
1294: MaxValues = pGraph->gMaxValues ;
1295: KnownValue = pGraph->gKnownValue ;
1296: iValidValues = pGraph->gTimeLine.iValidValues ;
1297:
1298: if (iValidValues < MaxValues)
1299: {
1300: // data have not wrapped around, so the oldest time
1301: // is started at 0.
1302: SimpleCase = TRUE ;
1303: iValidValues = (KnownValue % MaxValues) + 1 ;
1304: }
1305:
1306: iDataPoint = KnownValue % MaxValues ;
1307:
1308: if (!SimpleCase)
1309: {
1310: for (iIndex = iDataPoint+1 ; iIndex < MaxValues ; iIndex++)
1311: {
1312: if (!ExportLineValue (hFile, pGraph, iIndex, iDataPoint))
1313: {
1314: goto Exit0 ;
1315: }
1316: }
1317: }
1318:
1319: for (iIndex = 0 ; iIndex <= iDataPoint ; iIndex++)
1320: {
1321: if (!ExportLineValue (hFile, pGraph, iIndex, iDataPoint))
1322: {
1323: goto Exit0 ;
1324: }
1325: }
1326:
1327: return (TRUE) ;
1328:
1329: Exit0:
1330: return (FALSE) ;
1331:
1332: } // ExportCurrentChart
1333:
1334:
1335: void ExportChart (void)
1336: {
1337:
1338: PGRAPHSTRUCT pGraph ;
1339: HANDLE hFile = 0 ;
1340: LPTSTR pFileName = NULL ;
1341: INT ErrCode = 0 ;
1342:
1343: if (!(pGraph = pGraphs))
1344: {
1345: return ;
1346: }
1347:
1348: // see if there is anything to export..
1349: if (!(pGraph->pLineFirst))
1350: {
1351: return ;
1352: }
1353:
1354: SetHourglassCursor() ;
1355:
1356: if (ErrCode = ExportFileOpen (hWndGraph, &hFile, pGraph->gInterval, &pFileName))
1357: {
1358: goto Exit0 ;
1359: }
1360:
1361: if (!pFileName)
1362: {
1363: // this is the case when user cancel.
1364: goto Exit0 ;
1365: }
1366:
1367: // export the column labels
1368: if (!ExportChartLabels (hFile, pGraph))
1369: {
1370:
1371: ErrCode = ERR_EXPORT_FILE ;
1372: goto Exit0 ;
1373: }
1374:
1375: // export the lines
1376: if (PlayingBackLog())
1377: {
1378: if (!ExportLogChart (hFile, pGraph))
1379: {
1380: ErrCode = ERR_EXPORT_FILE ;
1381: goto Exit0 ;
1382: }
1383: }
1384: else
1385: {
1386: if (!ExportCurrentChart (hFile, pGraph))
1387: {
1388: ErrCode = ERR_EXPORT_FILE ;
1389: goto Exit0 ;
1390: }
1391: }
1392: Exit0:
1393:
1394: SetArrowCursor() ;
1395:
1396: if (hFile)
1397: {
1398: CloseHandle (hFile) ;
1399: }
1400:
1401: if (pFileName)
1402: {
1403: if (ErrCode)
1404: {
1405: DlgErrorBox (hWndGraph, ErrCode, pFileName) ;
1406: }
1407:
1408: MemoryFree (pFileName) ;
1409: }
1410:
1411: } // ExportChart
1412:
1413:
1414: typedef struct CHARTDATAPOINTSTRUCT
1415: {
1416: int iLogIndex ;
1417: int xDispDataPoint ;
1418: } CHARTDATAPOINT, *PCHARTDATAPOINT ;
1419:
1420: void PlaybackChartDataPoint (PCHARTDATAPOINT pChartDataPoint)
1421: { // PlaybackChartDataPoint
1422: int iDisplayTics ; // num visual points to display
1423: int iDisplayTic ;
1424: int iLogTic ;
1425: int iLogTicsMove ;
1426: BOOL bFirstTime = TRUE;
1427: int iLogTicsRemaining ;
1428: int numOfData, xDispDataPoint, rectWidth, xPos ;
1429: PGRAPHSTRUCT pGraph ;
1430:
1431: pGraph = GraphData (hWndGraph) ;
1432:
1433: iLogTicsRemaining = PlaybackLog.iSelectedTics ;
1434:
1435:
1436: // we only have iDisplayTics-1 points since
1437: // we have to use the first two sample points to
1438: // get the first data points.
1439: if (iLogTicsRemaining <= pGraphs->gMaxValues)
1440: {
1441: iDisplayTics = iLogTicsRemaining ;
1442: }
1443: else
1444: {
1445: iDisplayTics = pGraphs->gMaxValues ;
1446: }
1447:
1448: iDisplayTic = -1 ;
1449: iLogTic = PlaybackLog.StartIndexPos.iPosition ;
1450:
1451: numOfData = pGraph->gMaxValues - 1 ;
1452: rectWidth = pGraph->rectData.right - pGraph->rectData.left ;
1453: xDispDataPoint = pGraph->rectData.left ;
1454:
1455: while (iDisplayTics && numOfData)
1456: {
1457:
1458: if (!bFirstTime)
1459: {
1460: iDisplayTic++ ;
1461: }
1462: else
1463: {
1464: bFirstTime = FALSE ;
1465:
1466: // get the second sample data to form the first data point
1467: iLogTic++ ;
1468: iLogTicsRemaining-- ;
1469:
1470: iDisplayTic++ ;
1471: }
1472:
1473: pChartDataPoint[iDisplayTic].iLogIndex = iLogTic ;
1474: pChartDataPoint[iDisplayTic].xDispDataPoint = xDispDataPoint ;
1475:
1476: // setup DDA to get the index of the next sample point
1477: iLogTicsMove = DDA_DISTRIBUTE (iLogTicsRemaining, iDisplayTics) ;
1478: iLogTicsRemaining -= iLogTicsMove ;
1479: iLogTic += iLogTicsMove ;
1480:
1481:
1482: xPos = DDA_DISTRIBUTE (rectWidth, numOfData) ;
1483: xDispDataPoint += xPos ;
1484: numOfData-- ;
1485: rectWidth -= xPos ;
1486:
1487: iDisplayTics-- ;
1488:
1489: } // while
1490:
1491: } // PlaybackChartDataPoint
1492:
1493:
1494: BOOL
1495: BuildNewValueListForGraph (
1496: )
1497: {
1498: PGRAPHSTRUCT pGraph;
1499:
1500: pGraph = pGraphs; // set local pointer to global pointer
1501:
1502: return BuildValueListForSystems (
1503: pGraphs->pSystemFirst,
1504: pGraphs->pLineFirst);
1505:
1506: }
1507:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.