//==========================================================================// // 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 ) { return (PointerSeek (PlaybackLog.pHeader, lFileOffset)) ; } 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_PATH + 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. */ { LOGPOSITION LP ; PLOGINDEX pIndex ; PBOOKMARK pBookmarkDisk, pBookmark ; // LONG lFilePosition ; pIndex = IndexFromPosition (pLogPosition) ; LP = *pLogPosition ; pBookmark = NULL ; while (TRUE) { 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)) ; if (pBookmark) { *pBookmark = *pBookmarkDisk; pBookmark->pBookmarkNext = NULL ; } else return (FALSE); } if (pIndex && IsDataIndex (pIndex)) { LP.iPosition++ ; *pLogPosition = LP ; if (pBookmark) { pBookmark->iTic = PlaybackLog.iTotalTics ; BookmarkAppend (&PlaybackLog.pBookmarkFirst, pBookmark) ; } return (TRUE) ; } } } 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. */ { 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) ; } //==========================================================================// // Exported Functions // //==========================================================================// void PlaybackInitializeInstance (void) { PlaybackLog.iStatus = iPMStatusClosed ; PlaybackLog.hFile = NULL ; PlaybackLog.szFilePath = MemoryAllocate (FilePathLen * sizeof (TCHAR)) ; if (PlaybackLog.szFilePath) { lstrcpy (PlaybackLog.szFilePath, szDefaultLogFileName) ; } PlaybackLog.szFileTitle = MemoryAllocate (FilePathLen * sizeof (TCHAR)) ; if (PlaybackLog.szFileTitle) { lstrcpy (PlaybackLog.szFileTitle, szDefaultLogFileName) ; } } INT OpenPlayback ( LPTSTR lpszFilePath, LPTSTR lpszFileTitle ) { 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) ; } void CloseInputLog ( HWND hWndParent ) { 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 ) { LOGPOSITION LP ; int i ; LP = PlaybackLog.BeginIndexPos ; for (i = 0 ; i < iIndex ; i++) { if (!NextIndexPosition (&LP, FALSE)) return (FALSE) ; } *pLP = LP ; return (TRUE) ; } 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 ) { 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) ; } PPERFDATA LogDataFromPosition ( PPERFSYSTEM pSystem, PLOGPOSITION pLogPosition ) { PLOGINDEX pLogIndex ; if (!pLogPosition) return (NULL) ; pLogIndex = IndexFromPosition (pLogPosition) ; if (!pLogIndex) return (NULL) ; return (DataFromIndex (pLogIndex, pSystem->sysName)) ; } BOOL LogPositionSystemTime ( PLOGPOSITION pLP, SYSTEMTIME *pSystemTime ) /* Effect: Given a logposition, get the index entry for that position and return the system time stored therein. */ { PLOGINDEX pLogIndex ; pLogIndex = IndexFromPosition (pLP) ; if (!pLogIndex) return (FALSE) ; *pSystemTime = pLogIndex->SystemTime ; return TRUE; } int LogPositionIntervalSeconds ( PLOGPOSITION pLPStart, PLOGPOSITION pLPStop ) /* Effect: Return the time difference (in seconds) between the system times of the two specified log positions. */ { SYSTEMTIME SystemTimeStart ; SYSTEMTIME SystemTimeStop ; if (LogPositionSystemTime (pLPStart, &SystemTimeStart) && LogPositionSystemTime (pLPStop, &SystemTimeStop)) return (SystemTimeDifference (&SystemTimeStart, &SystemTimeStop, TRUE)) ; else return (0) ; } int PlaybackSelectedSeconds (void) { return (LogPositionIntervalSeconds (&PlaybackLog.StartIndexPos, &PlaybackLog.StopIndexPos)) ; } void BuildLogComputerList ( HWND hDlg, int DlgID ) { PPERFDATA pPerfData; int iNumSystem ; HWND hListBox = GetDlgItem (hDlg, DlgID) ; PLOGINDEX pLogIndex ; TCHAR szLoggedComputerName[MAX_PATH + 3] ; 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) ; if (LBFind (hListBox, szLoggedComputerName) != 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; } } } void PlaybackAddCounterName ( PLOGINDEX pIndex ) { PLOGCOUNTERNAME pLogCounterName = NULL, pListCounterName = NULL; 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) ; }