//==========================================================================//
// Includes //
//==========================================================================//
#include "perfmon.h"
#include "playback.h" // external declarations for this module
#include "bookmark.h" // for BookmarkAppend
#include "grafdata.h" // for ResetGraph
#include "perfdata.h" // for UpdateLinesForSystem
#include "perfmops.h" // for SystemTimeDateString
#include "log.h"
#include "pmemory.h" // for MemoryAllocate
#include "fileutil.h"
#include "utils.h"
#include "alert.h" // for ResetAlert
#include "report.h" // for ResetReport
NTSTATUS AddNamesToArray (LPTSTR pNames,
DWORD dwLastID,
LPWSTR *lpCounterId) ;
void PlaybackAddCounterName (PLOGINDEX pIndex) ;
//==========================================================================//
// Macros //
//==========================================================================//
#define PointerSeek(pBase, lFileOffset) \
((PVOID) ((PBYTE) pBase + lFileOffset))
//==========================================================================//
// Local Functions //
//==========================================================================//
PVOID PlaybackSeek (long lFileOffset)
{ // PlaybackSeek
return (PointerSeek (PlaybackLog.pHeader, lFileOffset)) ;
} // PlaybackSeek
PLOGINDEXBLOCK FirstIndexBlock (PLOGHEADER pLogHeader)
{
return ((PLOGINDEXBLOCK) PointerSeek (pLogHeader, pLogHeader->iLength)) ;
}
PLOGINDEX IndexFromPosition (PLOGPOSITION pLogPosition)
{
return (&pLogPosition->pIndexBlock->aIndexes [pLogPosition->iIndex]) ;
}
PPERFDATA DataFromIndex (PLOGINDEX pLogIndex,
LPTSTR lpszSystemName)
{
PPERFDATA pPerfData;
TCHAR szLoggedComputerName[MAX_COMPUTERNAME_LENGTH + 3] ;
int iNumSystem ;
// Note: NULL lpszSystemName means return first logged system name
// at the specified index.
pPerfData = PlaybackSeek (pLogIndex->lDataOffset) ;
for (iNumSystem = 0;
iNumSystem < pLogIndex->iSystemsLogged;
iNumSystem++)
{
if ( pPerfData &&
pPerfData->Signature[0] == (WCHAR)'P' &&
pPerfData->Signature[1] == (WCHAR)'E' &&
pPerfData->Signature[2] == (WCHAR)'R' &&
pPerfData->Signature[3] == (WCHAR)'F' )
{
GetPerfComputerName(pPerfData, szLoggedComputerName) ;
if (!lpszSystemName || strsamei(lpszSystemName, szLoggedComputerName))
{
return pPerfData ;
}
pPerfData = (PPERFDATA)((PBYTE) pPerfData +
pPerfData->TotalByteLength) ;
}
else
{
break ;
}
}
return NULL ;
}
PPERFDATA DataFromIndexPosition (PLOGPOSITION pLogPosition,
LPTSTR lpszSystemName)
{
PLOGINDEX pLogIndex ;
// long lDataFileOffset ;
pLogIndex = IndexFromPosition (pLogPosition) ;
return (DataFromIndex (pLogIndex, lpszSystemName)) ;
}
BOOL NextLogPosition (IN OUT PLOGPOSITION pLogPosition)
{
PLOGINDEXBLOCK pIndexBlock ;
if (pLogPosition->pIndexBlock->iNumIndexes == 0)
{
// no data in this index block. This is most likely
// a corrupted log file caused by system failure...
return (FALSE) ;
}
if (pLogPosition->iIndex == pLogPosition->pIndexBlock->iNumIndexes - 1)
{
if (pLogPosition->pIndexBlock->lNextBlockOffset)
{
pIndexBlock =
PlaybackSeek (pLogPosition->pIndexBlock->lNextBlockOffset) ;
if (pIndexBlock->iNumIndexes == 0)
{
// no data in the next index block. This is most likely
// a corrupted log file caused by system failure...
return (FALSE) ;
}
else
{
pLogPosition->pIndexBlock = pIndexBlock ;
pLogPosition->iIndex = 0 ;
return (TRUE) ;
}
}
else
return (FALSE) ;
}
else
{
pLogPosition->iIndex++ ;
return (TRUE) ;
}
}
BOOL NextIndexPosition (IN OUT PLOGPOSITION pLogPosition,
BOOL bCheckForNonDataIndexes)
/*
Effect: Set pLogPosition to the next log position from
the current position of pLogPosition if there is one.
Returns: Whether there was a next log position.
*/
{ // NextIndexPosition
LOGPOSITION LP ;
PLOGINDEX pIndex ;
PBOOKMARK pBookmarkDisk, pBookmark ;
// LONG lFilePosition ;
pIndex = IndexFromPosition (pLogPosition) ;
LP = *pLogPosition ;
pBookmark = NULL ;
while (TRUE)
{ // while
if (!NextLogPosition (&LP))
return (FALSE) ;
pIndex = IndexFromPosition (&LP) ;
if (pIndex && bCheckForNonDataIndexes && IsCounterNameIndex (pIndex))
{
PlaybackAddCounterName (pIndex) ;
}
if (pIndex && bCheckForNonDataIndexes && IsBookmarkIndex (pIndex))
{
if (pBookmark)
{
// this is the case when several bookmarks are
// found before any data index...
pBookmark->iTic = PlaybackLog.iTotalTics ;
BookmarkAppend (&PlaybackLog.pBookmarkFirst, pBookmark) ;
}
pBookmarkDisk = PlaybackSeek (pIndex->lDataOffset) ;
pBookmark = MemoryAllocate (sizeof (BOOKMARK)) ;
*pBookmark = *pBookmarkDisk;
pBookmark->pBookmarkNext = NULL ;
}
if (pIndex && IsDataIndex (pIndex))
{
LP.iPosition++ ;
*pLogPosition = LP ;
if (pBookmark)
{
pBookmark->iTic = PlaybackLog.iTotalTics ;
BookmarkAppend (&PlaybackLog.pBookmarkFirst, pBookmark) ;
}
return (TRUE) ;
}
} // while
} // NextIndexPosition
BOOL NextReLogIndexPosition (IN OUT PLOGPOSITION pLogPosition)
/*
Effect: Set pLogPosition to the next log position from
the current position of pLogPosition if there is one.
Will return bookmarks, counternames, or data.
Returns: Whether there was a next relog position.
*/
{ // NextReLogIndexPosition
LOGPOSITION LP ;
PLOGINDEX pIndex ;
// LONG lFilePosition ;
pIndex = IndexFromPosition (pLogPosition) ;
LP = *pLogPosition ;
if (!NextLogPosition (&LP))
return (FALSE) ;
pIndex = IndexFromPosition (&LP) ;
if (pIndex && IsDataIndex (pIndex))
{
LP.iPosition++ ;
}
*pLogPosition = LP ;
return (TRUE) ;
} // NextReLogIndexPosition
//==========================================================================//
// Exported Functions //
//==========================================================================//
void PlaybackInitializeInstance (void)
{ // PlaybackInitializeInstance
PlaybackLog.iStatus = iPMStatusClosed ;
PlaybackLog.hFile = NULL ;
PlaybackLog.szFilePath = MemoryAllocate (FilePathLen * sizeof (TCHAR)) ;
PlaybackLog.szFileTitle = MemoryAllocate (FilePathLen * sizeof (TCHAR)) ;
lstrcpy (PlaybackLog.szFilePath, szDefaultLogFileName) ;
lstrcpy (PlaybackLog.szFileTitle, szDefaultLogFileName) ;
} // PlaybackInitializeInstance
INT OpenPlayback (LPTSTR lpszFilePath, LPTSTR lpszFileTitle)
{ // OpenPlayback
BOOL bFirstTime = TRUE ;
lstrcpy (PlaybackLog.szFilePath, lpszFilePath) ;
lstrcpy (PlaybackLog.szFileTitle, lpszFileTitle) ;
PlaybackLog.hFile = FileHandleReadOnly (lpszFilePath) ;
if (!PlaybackLog.hFile || PlaybackLog.hFile == INVALID_HANDLE_VALUE)
{
return (ERR_CANT_OPEN) ;
}
PlaybackLog.pHeader = (PLOGHEADER) FileMap (PlaybackLog.hFile,
&PlaybackLog.hMapHandle) ;
if (!PlaybackLog.pHeader)
{
if (PlaybackLog.hMapHandle)
{
CloseHandle (PlaybackLog.hMapHandle) ;
}
CloseHandle (PlaybackLog.hFile) ;
return (ERR_CANT_OPEN) ;
}
if (!strsame (PlaybackLog.pHeader->szSignature, LogFileSignature))
{
FileUnMap((LPVOID)PlaybackLog.pHeader, PlaybackLog.hMapHandle) ;
CloseHandle (PlaybackLog.hFile) ;
return (ERR_BAD_LOG_FILE) ;
}
PlaybackLog.BeginIndexPos.pIndexBlock = FirstIndexBlock (PlaybackLog.pHeader) ;
PlaybackLog.BeginIndexPos.iIndex = 0 ;
PlaybackLog.BeginIndexPos.iPosition = 0 ;
PlaybackLog.pBookmarkFirst = NULL ;
PlaybackLog.iTotalTics = 1 ;
PlaybackLog.EndIndexPos = PlaybackLog.BeginIndexPos ;
while (NextIndexPosition (&PlaybackLog.EndIndexPos, TRUE))
{
if (bFirstTime)
{
// set the begin index to the first data index
bFirstTime = FALSE ;
PlaybackLog.BeginIndexPos.iIndex =
PlaybackLog.EndIndexPos.iIndex ;
}
else
{
PlaybackLog.iTotalTics++ ;
}
}
if (PlaybackLog.iTotalTics == 1 )
{
// no data inside the log file. It must be a corrupted
// log file
FileUnMap((LPVOID)PlaybackLog.pHeader, PlaybackLog.hMapHandle) ;
CloseHandle (PlaybackLog.hFile) ;
return (ERR_CORRUPT_LOG) ;
}
// PlaybackLog.StartIndexPos = PlaybackLog.BeginIndexPos ;
// getthe first data index
if (!LogPositionN (1, &(PlaybackLog.StartIndexPos)))
{
PlaybackLog.StartIndexPos = PlaybackLog.BeginIndexPos ;
}
PlaybackLog.StopIndexPos = PlaybackLog.EndIndexPos ;
PlaybackLog.StopIndexPos.iPosition =
min (PlaybackLog.StopIndexPos.iPosition,
PlaybackLog.iTotalTics - 1 ) ;
PlaybackLog.iSelectedTics = PlaybackLog.iTotalTics ;
PlaybackLog.iStatus = iPMStatusPlaying ;
return (0) ;
} // OpenPlayback
void CloseInputLog (HWND hWndParent)
{ // CloseInputLog
PBOOKMARK pBookmark, pNextBookmark ;
BOOL retCode, retCode1 ;
PLOGCOUNTERNAME pLogCounterName, pNextCounterName ;
UNREFERENCED_PARAMETER (hWndParent) ;
// free the bookmark list
for (pBookmark = PlaybackLog.pBookmarkFirst ;
pBookmark ;
pBookmark = pNextBookmark )
{
// save next bookmark and free current bookmark
pNextBookmark = pBookmark->pBookmarkNext ;
MemoryFree (pBookmark) ;
}
PlaybackLog.pBookmarkFirst = NULL ;
// free all counter names stuff
if (PlaybackLog.pBaseCounterNames)
{
MemoryFree (PlaybackLog.pBaseCounterNames) ;
}
PlaybackLog.pBaseCounterNames = NULL ;
PlaybackLog.lBaseCounterNameSize = 0 ;
PlaybackLog.lBaseCounterNameOffset = 0 ;
for (pLogCounterName = PlaybackLog.pLogCounterNameFirst ;
pLogCounterName ;
pLogCounterName = pNextCounterName)
{
pNextCounterName = pLogCounterName->pCounterNameNext ;
MemoryFree (pLogCounterName->pRemainNames) ;
MemoryFree (pLogCounterName) ;
}
PlaybackLog.pLogCounterNameFirst = NULL ;
retCode1 = FileUnMap((LPVOID)PlaybackLog.pHeader, PlaybackLog.hMapHandle) ;
retCode = CloseHandle (PlaybackLog.hFile) ;
PlaybackLog.iStatus = iPMStatusClosed ;
ResetGraphView (hWndGraph) ;
ResetAlertView (hWndAlert) ;
ResetLogView (hWndLog) ;
ResetReportView (hWndReport) ;
}
BOOL LogPositionN (int iIndex, PLOGPOSITION pLP)
{ // LogPositionN
LOGPOSITION LP ;
int i ;
LP = PlaybackLog.BeginIndexPos ;
for (i = 0 ;
i < iIndex ;
i++)
{
if (!NextIndexPosition (&LP, FALSE))
return (FALSE) ;
}
*pLP = LP ;
return (TRUE) ;
} // LogPositionN
PLOGINDEX PlaybackIndexN (int iIndex)
{
LOGPOSITION LP ;
int i ;
LP = PlaybackLog.BeginIndexPos ;
for (i = 0 ;
i < iIndex ;
i++)
{
if (!NextIndexPosition (&LP, FALSE))
return (NULL) ;
}
return (IndexFromPosition (&LP)) ;
}
BOOL PlaybackLines (PPERFSYSTEM pSystemFirst,
PLINE pLineFirst,
int iLogTic)
{ // PlaybackLines
PLOGINDEX pLogIndex ;
PPERFDATA pPerfData ;
PPERFSYSTEM pSystem ;
BOOL bAnyFound ;
pLogIndex = PlaybackIndexN (iLogTic) ;
if (!pLogIndex)
return (FALSE) ;
bAnyFound = FALSE ;
for (pSystem = pSystemFirst ;
pSystem ;
pSystem = pSystem->pSystemNext)
{ // for
pPerfData = DataFromIndex (pLogIndex, pSystem->sysName) ;
if (pPerfData)
{
UpdateLinesForSystem (pSystem->sysName,
pPerfData,
pLineFirst,
NULL) ;
bAnyFound = TRUE ;
}
else
{
FailedLinesForSystem (pSystem->sysName,
pPerfData,
pLineFirst) ;
}
}
return (bAnyFound) ;
} // PlaybackLines
PPERFDATA LogDataFromPosition (PPERFSYSTEM pSystem,
PLOGPOSITION pLogPosition)
{ // LogDataFromPosition
PLOGINDEX pLogIndex ;
if (!pLogPosition)
return (NULL) ;
pLogIndex = IndexFromPosition (pLogPosition) ;
if (!pLogIndex)
return (NULL) ;
return (DataFromIndex (pLogIndex, pSystem->sysName)) ;
} // LogDataFromPosition
BOOL LogPositionSystemTime (PLOGPOSITION pLP, SYSTEMTIME *pSystemTime)
/*
Effect: Given a logposition, get the index entry for that position
and return the system time stored therein.
*/
{ // LogPositionSystemTime
PLOGINDEX pLogIndex ;
pLogIndex = IndexFromPosition (pLP) ;
if (!pLogIndex)
return (FALSE) ;
*pSystemTime = pLogIndex->SystemTime ;
} // LogPositionSystemTime
int LogPositionIntervalSeconds (PLOGPOSITION pLPStart,
PLOGPOSITION pLPStop)
/*
Effect: Return the time difference (in seconds) between the
system times of the two specified log positions.
*/
{ // LogPositionIntervalSeconds
SYSTEMTIME SystemTimeStart ;
SYSTEMTIME SystemTimeStop ;
if (LogPositionSystemTime (pLPStart, &SystemTimeStart) &&
LogPositionSystemTime (pLPStop, &SystemTimeStop))
return (SystemTimeDifference (&SystemTimeStart, &SystemTimeStop)) ;
else
return (0) ;
} // LogPositionIntervalSeconds
int PlaybackSelectedSeconds (void)
{ // PlaybackSelectedSeconds
return (LogPositionIntervalSeconds (&PlaybackLog.StartIndexPos,
&PlaybackLog.StopIndexPos)) ;
} // PlaybackSelectedSeconds
void BuildLogComputerList (HWND hDlg, int DlgID)
{
PPERFDATA pPerfData;
int iNumSystem ;
HWND hListBox = GetDlgItem (hDlg, DlgID) ;
PLOGINDEX pLogIndex ;
TCHAR szLoggedComputerName[MAX_COMPUTERNAME_LENGTH + 3] ;
int Index ;
pLogIndex = IndexFromPosition (&(PlaybackLog.StartIndexPos)) ;
pPerfData = PlaybackSeek (pLogIndex->lDataOffset) ;
for (iNumSystem = 0;
iNumSystem < pLogIndex->iSystemsLogged;
iNumSystem++)
{
if ( pPerfData &&
pPerfData->Signature[0] == (WCHAR)'P' &&
pPerfData->Signature[1] == (WCHAR)'E' &&
pPerfData->Signature[2] == (WCHAR)'R' &&
pPerfData->Signature[3] == (WCHAR)'F' )
{
GetPerfComputerName(pPerfData, szLoggedComputerName) ;
Index = LBFind (hListBox, szLoggedComputerName) ;
if (Index != LB_ERR)
{
// computer name already exist, we must have reach the next
// block of perfdata
break ;
}
LBAdd (hListBox, szLoggedComputerName) ;
pPerfData = (PPERFDATA)((PBYTE) pPerfData +
pPerfData->TotalByteLength) ;
}
else
{
break;
}
}
} // BuildLogComputerList
void PlaybackAddCounterName (PLOGINDEX pIndex)
{
PLOGCOUNTERNAME pLogCounterName, pListCounterName ;
PLOGFILECOUNTERNAME pDiskCounterName ;
PVOID pCounterData ;
BOOL bExist = FALSE ;
pDiskCounterName = PlaybackSeek (pIndex->lDataOffset) ;
// check we have a record for this system
for (pListCounterName = PlaybackLog.pLogCounterNameFirst ;
pListCounterName ;
pListCounterName = pListCounterName->pCounterNameNext)
{
if (strsamei(pDiskCounterName->szComputer,
pListCounterName->CounterName.szComputer))
{
// found!
pLogCounterName = pListCounterName ;
bExist = TRUE ;
break ;
}
}
if (!bExist)
{
// new counter name record
if (!(pLogCounterName = MemoryAllocate (sizeof(LOGCOUNTERNAME))))
{
return ;
}
}
else
{
// free old memory in previous counter name record.
if (pLogCounterName->pRemainNames)
{
MemoryFree (pLogCounterName->pRemainNames) ;
}
pLogCounterName->pRemainNames = NULL ;
}
pLogCounterName->CounterName = *pDiskCounterName ;
if (pDiskCounterName->lBaseCounterNameOffset == 0)
{
// this is the base counter names,
// get the master copy of the counter names
if (!(pCounterData =
MemoryAllocate (pDiskCounterName->lUnmatchCounterNames)))
{
MemoryFree (pLogCounterName) ;
return ;
}
// free the old one if it exists.
if (PlaybackLog.pBaseCounterNames)
{
MemoryFree (PlaybackLog.pBaseCounterNames) ;
}
PlaybackLog.pBaseCounterNames = pCounterData ;
pCounterData =
PlaybackSeek (pDiskCounterName->lCurrentCounterNameOffset) ;
memcpy (PlaybackLog.pBaseCounterNames,
pCounterData,
pDiskCounterName->lUnmatchCounterNames) ;
PlaybackLog.lBaseCounterNameSize =
pDiskCounterName->lUnmatchCounterNames ;
PlaybackLog.lBaseCounterNameOffset =
pDiskCounterName->lBaseCounterNameOffset ;
}
else if (pDiskCounterName->lUnmatchCounterNames)
{
// this is not a based system and it has extra counter names
// allocate a buffer to hold them
pLogCounterName->pRemainNames =
MemoryAllocate (pDiskCounterName->lUnmatchCounterNames) ;
if (pLogCounterName->pRemainNames)
{
pCounterData =
PlaybackSeek (pDiskCounterName->lCurrentCounterNameOffset) ;
memcpy(pLogCounterName->pRemainNames,
pCounterData,
pDiskCounterName->lUnmatchCounterNames) ;
}
}
if (!bExist)
{
// now add the new counter name record to the linked list
if (!PlaybackLog.pLogCounterNameFirst)
{
PlaybackLog.pLogCounterNameFirst = pLogCounterName ;
}
else
{
for (pListCounterName = PlaybackLog.pLogCounterNameFirst ;
pListCounterName->pCounterNameNext ;
pListCounterName = pListCounterName->pCounterNameNext)
{
// do nothing until we get to the end of the list
;
}
pListCounterName->pCounterNameNext = pLogCounterName ;
}
}
} // PlaybackAddCounterName
LPWSTR *LogBuildNameTable (PPERFSYSTEM pSysInfo)
{
DWORD dwArraySize ;
PLOGCOUNTERNAME pCounterName ;
LPWSTR *lpCounterId = NULL ;
LPWSTR lpCounterNames ;
NTSTATUS Status ;
for (pCounterName = PlaybackLog.pLogCounterNameFirst ;
pCounterName ;
pCounterName = pCounterName->pCounterNameNext)
{
if (strsamei (pSysInfo->sysName, pCounterName->CounterName.szComputer))
{
// found the right system
break ;
}
}
if (!pCounterName)
{
goto ERROR_EXIT ;
}
dwArraySize = (pCounterName->CounterName.dwLastCounterId + 1)
* sizeof (LPWSTR) ;
lpCounterId = MemoryAllocate (dwArraySize +
pCounterName->CounterName.lMatchLength +
pCounterName->CounterName.lUnmatchCounterNames ) ;
if (!lpCounterId)
{
goto ERROR_EXIT ;
}
// initialize pointers into buffer
lpCounterNames = (LPWSTR)((LPBYTE)lpCounterId + dwArraySize);
if (pCounterName->CounterName.lBaseCounterNameOffset == 0)
{
// this is the base system
memcpy(lpCounterNames,
PlaybackLog.pBaseCounterNames,
PlaybackLog.lBaseCounterNameSize) ;
}
else
{
// copy the matched portion from the base system
memcpy(lpCounterNames,
PlaybackLog.pBaseCounterNames,
pCounterName->CounterName.lMatchLength) ;
// copy the unmatched portion
if (pCounterName->CounterName.lUnmatchCounterNames)
{
memcpy(((PBYTE)lpCounterNames +
pCounterName->CounterName.lMatchLength),
pCounterName->pRemainNames,
pCounterName->CounterName.lUnmatchCounterNames) ;
}
}
Status = AddNamesToArray (lpCounterNames,
pCounterName->CounterName.dwLastCounterId,
lpCounterId) ;
if (Status != ERROR_SUCCESS)
{
goto ERROR_EXIT ;
}
pSysInfo->CounterInfo.dwLastId =
pCounterName->CounterName.dwLastCounterId ;
pSysInfo->CounterInfo.dwLangId =
pCounterName->CounterName.dwLangId ;
pSysInfo->CounterInfo.dwHelpSize = 0 ;
pSysInfo->CounterInfo.dwCounterSize =
pCounterName->CounterName.lMatchLength +
pCounterName->CounterName.lUnmatchCounterNames ;
return (lpCounterId) ;
ERROR_EXIT:
if (lpCounterId)
{
MemoryFree (lpCounterId) ;
}
return (NULL) ;
} // LogBuildNameTable