windows-nt/Source/XPSP1/NT/sdktools/perfmon/playback.c
2020-09-26 16:20:57 +08:00

778 lines
22 KiB
C

//==========================================================================//
// 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) ;
}