Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1933 lines
76 KiB

/*++
Copyright (C) 1996-1999 Microsoft Corporation
Module Name:
log_pm.c
Abstract:
<abstract>
--*/
#include <windows.h>
#include "strsafe.h"
#include <limits.h>
#include <pdh.h>
#include "pdhidef.h"
#include "perftype.h"
#include "log_pm.h"
#include "pdhmsg.h"
#include "perftype.h"
#include "perfdata.h"
#define PointerSeek(pBase, lFileOffset) ((PVOID) ((PBYTE) pBase + lFileOffset))
int
PdhiComparePmLogInstance(
PPDHI_LOG_COUNTER pCounter,
LPWSTR szInstance,
DWORD dwInstance,
LPWSTR szParent,
BOOL bUpdate
)
{
int iResult = 0;
if ((pCounter->szInstance != NULL && pCounter->szInstance[0] != L'\0')
&& (szInstance != NULL && szInstance[0] != L'\0')) {
iResult = lstrcmpiW(szInstance, pCounter->szInstance);
if (iResult != 0 && dwInstance != 0 && dwInstance != PERF_NO_UNIQUE_ID
&& (pCounter->dwInstance == 0 || pCounter->dwInstance == PERF_NO_UNIQUE_ID)) {
DWORD dwNewInstance = lstrlenW(szInstance) + 20;
LPWSTR szNewInstance = (LPWSTR) G_ALLOC(sizeof(WCHAR) * dwNewInstance);
if (szNewInstance != NULL) {
StringCchPrintfW(szNewInstance, dwNewInstance, L"%ws#%d", szInstance, dwInstance);
iResult = lstrcmpiW(szNewInstance, pCounter->szInstance);
if (iResult == 0) {
dwInstance = pCounter->dwInstance;
}
G_FREE(szNewInstance);
}
}
}
else if ((pCounter->szInstance != NULL && pCounter->szInstance[0] != L'\0')
&& (szInstance == NULL || szInstance[0] == L'\0')) {
iResult = -1;
}
else if ((pCounter->szInstance == NULL || pCounter->szInstance[0] == L'\0')
&& (szInstance != NULL && szInstance[0] != L'\0')) {
iResult = 1;
}
if (iResult != 0) goto Cleanup;
iResult = (dwInstance < pCounter->dwInstance) ? (-1) : ((dwInstance > pCounter->dwInstance) ? (1) : (0));
if (iResult != 0) goto Cleanup;
if ((pCounter->szParent != NULL && pCounter->szParent[0] != L'\0')
&& (szParent != NULL && szParent[0] != L'\0')) {
iResult = lstrcmpiW(szParent, pCounter->szParent);
}
else if ((pCounter->szParent != NULL && pCounter->szParent[0] != L'\0')
&& (szParent == NULL || szParent[0] == L'\0')) {
iResult = -1;
}
else if ((pCounter->szParent == NULL || pCounter->szParent[0] == L'\0')
&& (szParent != NULL && szParent[0] != L'\0')) {
iResult = 1;
}
Cleanup:
return iResult;
}
PPDHI_LOG_COUNTER
PdhiFindPmCounterInstance(
PPDHI_LOG_OBJECT pObject,
LPWSTR szCounter,
DWORD dwCounterType,
DWORD dwDefaultScale,
LPWSTR szInstance,
DWORD dwInstance,
LPWSTR szParent,
DWORD dwParent,
LPDWORD pdwIndex,
BOOL bInstance,
BOOL bInsert
)
{
PPDHI_LOG_COUNTER pCounter = NULL;
PPDHI_LOG_COUNTER pNode = NULL;
PPDHI_LOG_COUNTER * pStack[MAX_BTREE_DEPTH];
PPDHI_LOG_COUNTER * pLink;
int dwStack = 0;
PPDHI_LOG_COUNTER pParent;
PPDHI_LOG_COUNTER pSibling;
PPDHI_LOG_COUNTER pChild;
int iCompare;
HRESULT hr;
if (bInstance) {
pStack[dwStack ++] = & (pObject->InstTable);
pCounter = pObject->InstTable;
}
else {
pStack[dwStack ++] = & (pObject->CtrTable);
pCounter = pObject->CtrTable;
}
while (pCounter != NULL) {
if (bInstance) {
iCompare = PdhiComparePmLogInstance(pCounter, szInstance, dwInstance, szParent, bInsert);
}
else {
iCompare = lstrcmpiW(szCounter, pCounter->szCounter);
}
if (iCompare < 0) {
pStack[dwStack ++] = & (pCounter->left);
pCounter = pCounter->left;
}
else if (iCompare > 0) {
pStack[dwStack ++] = & (pCounter->right);
pCounter = pCounter->right;
}
else {
break;
}
}
if (bInsert) {
if (pCounter == NULL) {
DWORD dwCounterLen = lstrlenW(szCounter) + 1;
DWORD dwInstanceLen = 0;
DWORD dwParentLen = 0;
DWORD dwBufSize = sizeof(PDHI_LOG_COUNTER) + sizeof(WCHAR) * dwCounterLen;
if (szInstance != NULL) {
dwInstanceLen = lstrlenW(szInstance) + 1;
dwBufSize += (sizeof(WCHAR) * dwInstanceLen);
}
else {
dwBufSize += sizeof(WCHAR);
}
if (szParent != NULL) {
dwParentLen = lstrlenW(szParent) + 1;
dwBufSize += (sizeof(WCHAR) * dwParentLen);
}
else {
dwBufSize += sizeof(WCHAR);
}
pCounter = G_ALLOC(dwBufSize);
if (pCounter == NULL) goto Cleanup;
if (bInstance) {
pCounter->next = pObject->InstList;
pObject->InstList = pCounter;
}
else {
pCounter->next = pObject->CtrList;
pObject->CtrList = pCounter;
}
pCounter->bIsRed = TRUE;
pCounter->left = NULL;
pCounter->right = NULL;
pCounter->dwParent = dwParent;
pCounter->TimeStamp = 0;
pCounter->dwInstance = dwInstance;
pCounter->dwCounterID = (* pdwIndex);
if (! bInstance) {
pCounter->dwCounterType = dwCounterType;
pCounter->dwDefaultScale = dwDefaultScale;
}
if (szCounter == NULL || szCounter[0] == L'\0') {
pCounter->szCounter = NULL;
}
else {
pCounter->szCounter = (LPWSTR) (((PCHAR) pCounter) + sizeof(PDHI_LOG_COUNTER));
hr = StringCchCopyW(pCounter->szCounter, dwCounterLen, szCounter);
if (FAILED(hr)) {
G_FREE(pCounter);
pCounter = NULL;
goto Cleanup;
}
}
if (szInstance == NULL || szInstance[0] == L'\0') {
pCounter->szInstance = NULL;
}
else {
pCounter->szInstance = (LPWSTR) (((PCHAR) pCounter) + sizeof(PDHI_LOG_COUNTER)
+ sizeof(WCHAR) * dwCounterLen);
hr = StringCchCopyW(pCounter->szInstance, dwInstanceLen, szInstance);
if (FAILED(hr)) {
G_FREE(pCounter);
pCounter = NULL;
goto Cleanup;
}
}
if (szParent == NULL || szParent[0] == L'\0') {
pCounter->szParent = NULL;
}
else {
if (pCounter->szInstance != NULL) {
pCounter->szParent = (LPWSTR) (((PCHAR) pCounter)
+ sizeof(PDHI_LOG_COUNTER) + sizeof(WCHAR) * (dwCounterLen + dwInstanceLen));
}
else {
pCounter->szParent = (LPWSTR) (((PCHAR) pCounter) + sizeof(PDHI_LOG_COUNTER)
+ sizeof(WCHAR) * dwCounterLen);
}
hr = StringCchCopyW(pCounter->szParent, dwParentLen, szParent);
if (FAILED(hr)) {
G_FREE(pCounter);
pCounter = NULL;
goto Cleanup;
}
}
pLink = pStack[-- dwStack];
* pLink = pCounter;
pChild = NULL;
pNode = pCounter;
while (dwStack > 0) {
pLink = pStack[-- dwStack];
pParent = * pLink;
if (! pParent->bIsRed) {
pSibling = (pParent->left == pNode) ? pParent->right : pParent->left;
if (pSibling && pSibling->bIsRed) {
pNode->bIsRed = FALSE;
pSibling->bIsRed = FALSE;
pParent->bIsRed = TRUE;
}
else {
if (pChild && pChild->bIsRed) {
if (pChild == pNode->left) {
if (pNode == pParent->left) {
pParent->bIsRed = TRUE;
pParent->left = pNode->right;
pNode->right = pParent;
pNode->bIsRed = FALSE;
* pLink = pNode;
}
else {
pParent->bIsRed = TRUE;
pParent->right = pChild->left;
pChild->left = pParent;
pNode->left = pChild->right;
pChild->right = pNode;
pChild->bIsRed = FALSE;
* pLink = pChild;
}
}
else {
if (pNode == pParent->right) {
pParent->bIsRed = TRUE;
pParent->right = pNode->left;
pNode->left = pParent;
pNode->bIsRed = FALSE;
* pLink = pNode;
}
else {
pParent->bIsRed = TRUE;
pParent->left = pChild->right;
pChild->right = pParent;
pNode->right = pChild->left;
pChild->left = pNode;
pChild->bIsRed = FALSE;
* pLink = pChild;
}
}
}
break;
}
}
pChild = pNode;
pNode = pParent;
}
if (bInstance) {
pObject->InstTable->bIsRed = FALSE;
}
else {
pObject->CtrTable->bIsRed = FALSE;
}
}
else if (bInstance) {
pCounter->dwCounterType ++;
if (pCounter->dwCounterType > pCounter->dwDefaultScale) {
pCounter->dwDefaultScale = pCounter->dwCounterType;
}
}
}
else if (pCounter != NULL) {
* pdwIndex = pCounter->dwCounterID;
}
Cleanup:
return pCounter;
}
PDH_FUNCTION
PdhiBuildPmLogIndexTable(
PPLAYBACKLOG pPmLog
)
{
PDH_STATUS Status = ERROR_SUCCESS;
PLOGHEADER pLogHeader = (PLOGHEADER) pPmLog->pHeader;
PLOGINDEXBLOCK pIndexBlock = NULL;
DWORD dwOffset = pLogHeader->iLength;
DWORD dwIndex = 0;
int i;
if (dwOffset == sizeof(LOGHEADER)) {
while (dwOffset != 0 && dwOffset < pPmLog->llFileSize) {
pIndexBlock = (PLOGINDEXBLOCK) PointerSeek(pLogHeader, dwOffset);
dwIndex += pIndexBlock->iNumIndexes;
dwOffset = pIndexBlock->lNextBlockOffset;
}
if (dwOffset >= pPmLog->llFileSize) {
Status = PDH_LOG_FILE_OPEN_ERROR;
goto Cleanup;
}
pPmLog->dwLastIndex = dwIndex;
G_FREE(pPmLog->LogIndexTable);
pPmLog->LogIndexTable = G_ALLOC(dwIndex * sizeof(PLOGINDEX));
if (pPmLog->LogIndexTable == NULL) {
Status = PDH_MEMORY_ALLOCATION_FAILURE;
goto Cleanup;
}
dwIndex = 0;
dwOffset = pLogHeader->iLength;
while (dwOffset != 0 && dwOffset < pPmLog->llFileSize) {
pIndexBlock = (PLOGINDEXBLOCK) PointerSeek(pLogHeader, dwOffset);
for (i = 0; i < pIndexBlock->iNumIndexes; i ++) {
pPmLog->LogIndexTable[dwIndex + i] = & (pIndexBlock->aIndexes[i]);
}
dwIndex += pIndexBlock->iNumIndexes;
dwOffset = pIndexBlock->lNextBlockOffset;
}
if (dwOffset >= pPmLog->llFileSize) {
Status = PDH_LOG_FILE_OPEN_ERROR;
goto Cleanup;
}
}
else {
Status = PDH_INVALID_ARGUMENT;
}
Cleanup:
if (Status != ERROR_SUCCESS) {
G_FREE(pPmLog->LogIndexTable);
pPmLog->dwLastIndex = 0;
pPmLog->dwCurrentIndex = 0;
}
return Status;
}
void
PdhiFreeCounterStringNode(
PPDHI_PM_STRING pString,
DWORD dwLevel
)
{
if (pString != NULL) {
if (pString->left != NULL) {
PdhiFreeCounterStringNode(pString->left, dwLevel + 1);
}
if (pString->right != NULL) {
PdhiFreeCounterStringNode(pString->right, dwLevel + 1);
}
G_FREE(pString);
}
}
void
PdhiFreePmMachineList(
PPLAYBACKLOG pPmLog
)
{
PPMLOG_COUNTERNAMES pMachine = pPmLog->pFirstCounterNameTables;
PPMLOG_COUNTERNAMES pTmpMachine;
while (pMachine != NULL) {
pTmpMachine = pMachine;
pMachine = pTmpMachine->pNext;
PdhiFreeCounterStringNode(pTmpMachine->StringTree, 0);
G_FREE(pTmpMachine);
}
}
PPDHI_PM_STRING
PdhiFindPmString(
PPMLOG_COUNTERNAMES pMachine,
LPCWSTR szString,
LPDWORD pdwIndex,
BOOL bInsert
)
{
PDH_STATUS Status = ERROR_SUCCESS;
PPDHI_PM_STRING * pStack[MAX_BTREE_DEPTH];
int iStack = 0;
int iCompare = 0;
PPDHI_PM_STRING pString = pMachine->StringTree;
PPDHI_PM_STRING * pLink;
PPDHI_PM_STRING pNode;
PPDHI_PM_STRING pParent;
PPDHI_PM_STRING pSibling;
PPDHI_PM_STRING pChild;
pStack[iStack ++] = & pMachine->StringTree;
while (pString != NULL) {
iCompare = lstrcmpiW(szString, pString->szString);
if (iCompare > 0) {
if (iStack >= MAX_BTREE_DEPTH) {
Status = PDH_UNABLE_READ_LOG_HEADER;
break;
}
pStack[iStack ++] = & (pString->right);
pString = pString->right;
}
else if (iCompare < 0) {
if (iStack >= MAX_BTREE_DEPTH) {
Status = PDH_UNABLE_READ_LOG_HEADER;
break;
}
pStack[iStack ++] = & (pString->left);
pString = pString->left;
}
else {
break;
}
}
if (Status != ERROR_SUCCESS) goto Cleanup;
if (pString != NULL) {
if (pdwIndex != NULL) {
* pdwIndex = pString->dwIndex;
}
}
else if (bInsert && pdwIndex != NULL) {
pString = G_ALLOC(sizeof(PDHI_PM_STRING));
if (pString != NULL) {
pString->szString = (LPWSTR) szString;
pString->dwIndex = * pdwIndex;
pString->bIsRed = TRUE;
pString->left = NULL;
pString->right = NULL;
pLink = pStack[-- iStack];
* pLink = pString;
pNode = pString;
pChild = NULL;
while (iStack > 0) {
pLink = pStack[-- iStack];
pParent = * pLink;
if (! pParent->bIsRed) {
pSibling = (pParent->left == pNode) ? pParent->right : pParent->left;
if (pSibling && pSibling->bIsRed) {
pNode->bIsRed = FALSE;
pSibling->bIsRed = FALSE;
pParent->bIsRed = TRUE;
}
else {
if (pChild && pChild->bIsRed) {
if (pChild == pNode->left) {
if (pNode == pParent->left) {
pParent->bIsRed = TRUE;
pParent->left = pNode->right;
pNode->right = pParent;
pNode->bIsRed = FALSE;
* pLink = pNode;
}
else {
pParent->bIsRed = TRUE;
pParent->right = pChild->left;
pChild->left = pParent;
pNode->left = pChild->right;
pChild->right = pNode;
pChild->bIsRed = FALSE;
* pLink = pChild;
}
}
else {
if (pNode == pParent->right) {
pParent->bIsRed = TRUE;
pParent->right = pNode->left;
pNode->left = pParent;
pNode->bIsRed = FALSE;
* pLink = pNode;
}
else {
pParent->bIsRed = TRUE;
pParent->left = pChild->right;
pChild->right = pParent;
pNode->right = pChild->left;
pChild->left = pNode;
pChild->bIsRed = FALSE;
* pLink = pChild;
}
}
}
break;
}
}
pChild = pNode;
pNode = pParent;
}
pMachine->StringTree->bIsRed = FALSE;
}
else {
Status = PDH_MEMORY_ALLOCATION_FAILURE;
}
}
Cleanup:
if (Status != ERROR_SUCCESS) SetLastError(Status);
return pString;
}
PDH_FUNCTION
PdhiBuildPmLogStringTable(
PPLAYBACKLOG pPmLog,
PLOGFILECOUNTERNAME pLogName,
PPMLOG_COUNTERNAMES pMachine,
long lSize
)
{
PDH_STATUS Status = ERROR_SUCCESS;
PPDHI_PM_STRING pString;
LPWSTR szName;
DWORD dwName;
DWORD dwIndex;
long lUsed = 0;
if (lSize > pLogName->lUnmatchCounterNames
|| pLogName->lCurrentCounterNameOffset < 0
|| pLogName->lCurrentCounterNameOffset >= pPmLog->llFileSize
|| pLogName->lCurrentCounterNameOffset + pLogName->lUnmatchCounterNames > pPmLog->llFileSize) {
Status = PDH_UNABLE_READ_LOG_HEADER;
}
else if (pLogName->lBaseCounterNameOffset > 0) {
PLOGFILECOUNTERNAME pBaseName = (PLOGFILECOUNTERNAME)
PointerSeek(pPmLog->pHeader, pLogName->lBaseCounterNameOffset);
Status = PdhiBuildPmLogStringTable(pPmLog, pBaseName, pMachine, pLogName->lMatchLength);
}
if (Status != ERROR_SUCCESS) goto Cleanup;
szName = (LPWSTR) PointerSeek(pPmLog->pHeader, pLogName->lCurrentCounterNameOffset);
while (Status == ERROR_SUCCESS && lUsed <= lSize && szName[0] != L'\0') {
dwIndex = wcstoul(szName, NULL, 10);
if (dwIndex > 0 && dwIndex <= pMachine->dwLastIndex) {
dwName = lstrlenW(szName) + 1;
lUsed += (sizeof(WCHAR) * dwName);
if (lUsed <= lSize) {
szName += dwName;
pMachine->szNameTable[dwIndex] = szName;
pString = PdhiFindPmString(pMachine, szName, & dwIndex, TRUE);
if (pString == NULL) Status = GetLastError();
}
}
dwName = lstrlenW(szName) + 1;
lUsed += (sizeof(WCHAR) * dwName);
szName += dwName;
}
Cleanup:
return Status;
}
DWORD
PdhiLookupLogPerfIndexByName(
PPLAYBACKLOG pPlaybackLog,
LPCWSTR szMachineName,
DWORD dwLangId,
DWORD dwLastId,
LPCWSTR szNameBuffer
)
{
DWORD dwIndex = 0;
PDH_STATUS Status = PDH_CSTATUS_NO_MACHINE;
PPMLOG_COUNTERNAMES pMachine = pPlaybackLog->pFirstCounterNameTables;
while (pMachine != NULL) {
if (lstrcmpiW(szMachineName, pMachine->szSystemName) == 0) break;
pMachine = pMachine->pNext;
}
if (pMachine != NULL) {
PPDHI_PM_STRING pString = PdhiFindPmString(pMachine, szNameBuffer, & dwIndex, FALSE);
if (pString == NULL) {
Status = GetLastError();
dwIndex = wcstoul(szNameBuffer, NULL, 10);
}
}
if (dwIndex == 0) SetLastError(Status);
return dwIndex;
}
LPCWSTR
PdhiLookupLogPerfNameByIndex(
PPLAYBACKLOG pPlaybackLog,
LPCWSTR szMachineName,
DWORD dwLangId,
DWORD dwIndex
)
{
PPMLOG_COUNTERNAMES pMachine = pPlaybackLog->pFirstCounterNameTables;
LPWSTR szReturn = NULL;
static WCHAR szNumber[16];
while (pMachine != NULL) {
if (lstrcmpiW(szMachineName, pMachine->szSystemName) == 0) break;
pMachine = pMachine->pNext;
}
if (pMachine != NULL) {
if (dwIndex <= pMachine->dwLastIndex && dwLangId == pMachine->dwLangId) {
szReturn = pMachine->szNameTable[dwIndex];
}
if (szReturn == NULL) {
SetLastError(PDH_CSTATUS_NO_OBJECT);
ZeroMemory(szNumber, sizeof(szNumber));
_ltow(dwIndex, szNumber, 10);
szReturn = szNumber;
}
}
else {
SetLastError(PDH_CSTATUS_NO_MACHINE);
}
return (LPCWSTR) szReturn;
}
PDH_FUNCTION
PdhiCachePerfDataBlock(
PPLAYBACKLOG pPmLog,
PLOGINDEX pIndex
)
{
PDH_STATUS Status = ERROR_SUCCESS;
PPERF_DATA_BLOCK pBlock;
PPERF_OBJECT_TYPE pObject;
PPERF_COUNTER_DEFINITION pCounter;
int i;
LPWSTR szMachine;
LPWSTR szLogMachine = NULL;
LPWSTR szObject;
DWORD dwObjects;
PPDHI_LOG_MACHINE pLoggedMachine = NULL;
PPDHI_LOG_OBJECT pLoggedObject = NULL;
PPMLOG_COUNTERNAMES pCounterTable = NULL;
HRESULT hr;
for (i = 0; i < pIndex->iSystemsLogged; i ++) {
if (i == 0) {
pBlock = (PPERF_DATA_BLOCK) PointerSeek(pPmLog->pHeader, pIndex->lDataOffset);
}
else {
pBlock = (PPERF_DATA_BLOCK) PointerSeek(pBlock, pBlock->TotalByteLength);
}
if (pBlock->TotalByteLength <= sizeof(PERF_DATA_BLOCK) || pBlock->HeaderLength <= sizeof(PERF_DATA_BLOCK)) {
continue;
}
dwObjects = pBlock->NumObjectTypes;
szMachine = (LPWSTR) PointerSeek(pBlock, sizeof(PERF_DATA_BLOCK));
G_FREE(szLogMachine);
szLogMachine = G_ALLOC((lstrlenW(szMachine) + 3) * sizeof(WCHAR));
if (szLogMachine == NULL) {
Status = PDH_MEMORY_ALLOCATION_FAILURE;
break;
}
hr = StringCchPrintfW(szLogMachine, lstrlenW(szMachine) + 3, L"\\\\%ws", szMachine);
if (FAILED(hr)) {
Status = PDH_MEMORY_ALLOCATION_FAILURE;
break;
}
pLoggedMachine = PdhiFindLogMachine(& pPmLog->MachineList, szLogMachine, TRUE);
if (pLoggedMachine == NULL) {
Status = PDH_MEMORY_ALLOCATION_FAILURE;
break;
}
pCounterTable = pPmLog->pFirstCounterNameTables;
while (pCounterTable != NULL) {
if (lstrcmpiW(pCounterTable->szSystemName, szLogMachine) == 0) break;
pCounterTable = pCounterTable->pNext;
}
if (pCounterTable == NULL) continue;
pObject = FirstObject(pBlock);
while ((pObject != NULL) && (dwObjects > 0)) {
dwObjects --;
if (pObject->TotalByteLength > sizeof(PERF_OBJECT_TYPE)
&& pObject->DefinitionLength > sizeof(PERF_OBJECT_TYPE)
&& pObject->ObjectNameTitleIndex <= pCounterTable->dwLastIndex) {
szObject = (LPWSTR) PdhiLookupLogPerfNameByIndex(pPmLog,
szLogMachine,
pCounterTable->dwLangId,
pObject->ObjectNameTitleIndex);
if (szObject != NULL) {
pLoggedObject = PdhiFindLogObject(pLoggedMachine,
& pLoggedMachine->ObjTable,
szObject,
TRUE);
if (pLoggedObject == NULL) {
Status = PDH_MEMORY_ALLOCATION_FAILURE;
break;
}
pLoggedObject->bNeedExpand = TRUE;
pLoggedObject->dwObject = pObject->ObjectNameTitleIndex;
}
}
pObject = (dwObjects > 0) ? NextObject(pBlock, pObject) : NULL;
}
}
G_FREE(szLogMachine);
return Status;
}
PDH_FUNCTION
PdhiCachePmLogHeader(
PPLAYBACKLOG pPmLog
)
{
PDH_STATUS Status = ERROR_SUCCESS;
PLOGINDEX * IndexTable;
DWORD i;
int iMaxSystemLogged = -1;
DWORD dwIndex = 0;
if (pPmLog == NULL) {
Status = PDH_INVALID_ARGUMENT;
goto Cleanup;
}
else if (pPmLog->pFirstCounterNameTables != NULL && pPmLog->MachineList != NULL) {
goto Cleanup;
}
IndexTable = pPmLog->LogIndexTable;
for (i = 0; i < pPmLog->dwLastIndex; i ++) {
// Ignore first uFlags 0x00000000 and LogFileIndexBookmark index entries.
//
if ((IndexTable[i]->uFlags & LogFileIndexCounterName) != 0) {
// For LogFileIndexCounterName index entries, cache counter name/explain string table.
if (IndexTable[i]->lDataOffset < pPmLog->llFileSize) {
PLOGFILECOUNTERNAME pLogName = (PLOGFILECOUNTERNAME)
PointerSeek(pPmLog->pHeader, IndexTable[i]->lDataOffset);
PPMLOG_COUNTERNAMES pMachine = pPmLog->pFirstCounterNameTables;
while (pMachine != NULL) {
if (lstrcmpiW(pMachine->szSystemName, pLogName->szComputer) == 0) break;
pMachine = pMachine->pNext;
}
if (pMachine == NULL) {
pMachine = (PPMLOG_COUNTERNAMES) G_ALLOC(
sizeof(PMLOG_COUNTERNAMES) + sizeof(LPWSTR) * (pLogName->dwLastCounterId + 1));
if (pMachine != NULL) {
pMachine->szSystemName = pLogName->szComputer;
pMachine->szNameTable = PointerSeek(pMachine, sizeof(PMLOG_COUNTERNAMES));
pMachine->dwLangId = pLogName->dwLangId;
pMachine->dwLastIndex = pLogName->dwLastCounterId;
pMachine->pNext = pPmLog->pFirstCounterNameTables;
pPmLog->pFirstCounterNameTables = pMachine;
}
else {
Status = PDH_MEMORY_ALLOCATION_FAILURE;
}
}
if (Status == ERROR_SUCCESS) {
Status = PdhiBuildPmLogStringTable(pPmLog, pLogName, pMachine, pLogName->lUnmatchCounterNames);
}
}
else {
Status = PDH_UNABLE_READ_LOG_HEADER;
}
if (Status != ERROR_SUCCESS) break;
}
else if ((IndexTable[i]->uFlags & LogFileIndexData) != 0) {
// Process first LogFileIndexData block for initial machine-object cache structure.
//
if (IndexTable[i]->iSystemsLogged > iMaxSystemLogged) {
iMaxSystemLogged = IndexTable[i]->iSystemsLogged;
dwIndex = i;
}
}
}
if (Status == ERROR_SUCCESS) {
Status = (iMaxSystemLogged > 0) ? PdhiCachePerfDataBlock(pPmLog, IndexTable[dwIndex])
: PDH_UNABLE_READ_LOG_HEADER;
}
Cleanup:
return Status;
}
PPERF_DATA_BLOCK
PdhiDataFromIndex(
PPLAYBACKLOG pPlaybackLog,
PLOGINDEX pLogIndex,
LPCWSTR lpszSystemName
)
{
PPERF_DATA_BLOCK pPerfData;
PPERF_DATA_BLOCK pRtnBlock = NULL;
LPWSTR szLoggedComputerName = NULL;
int iNumSystem ;
// Note: NULL lpszSystemName means return first logged system name
// at the specified index.
pPerfData = PointerSeek(pPlaybackLog->pHeader, 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') {
szLoggedComputerName = (LPWSTR) PointerSeek(pPerfData, pPerfData->SystemNameOffset);
if (lpszSystemName == NULL) {
pRtnBlock = pPerfData;
break;
}
else if (lstrlenW(lpszSystemName) > 2 && lpszSystemName[0] == L'\\' && lpszSystemName[1] == L'\\') {
if (lstrcmpiW(szLoggedComputerName, & (lpszSystemName[2])) == 0) {
pRtnBlock = pPerfData;
break;
}
}
else if (lstrcmpiW(szLoggedComputerName, lpszSystemName) == 0) {
pRtnBlock = pPerfData;
break;
}
pPerfData = (PPERFDATA)((PBYTE) pPerfData + pPerfData->TotalByteLength);
}
else {
break;
}
}
return pRtnBlock;
}
PPERF_OBJECT_TYPE
PdhiFindPerfObject(
PPERF_DATA_BLOCK pBlock,
DWORD dwObject
)
{
DWORD dwCount = pBlock->NumObjectTypes;
PPERF_OBJECT_TYPE pObject = FirstObject(pBlock);
while (pObject != NULL && dwCount > 0) {
dwCount --;
if (pObject->ObjectNameTitleIndex == dwObject) break;
pObject = (dwCount > 0) ? NextObject(pBlock, pObject) : NULL;
}
return pObject;
}
PDH_FUNCTION
PdhiCachePmLogObject(
PPLAYBACKLOG pPmLog,
LPWSTR szMachineName,
LPWSTR szObjectName
)
{
PDH_STATUS Status = ERROR_SUCCESS;
PPMLOG_COUNTERNAMES pCounterTable = NULL;
PPDHI_LOG_MACHINE pLogMachine = PdhiFindLogMachine(& pPmLog->MachineList, szMachineName, FALSE);
PPDHI_LOG_OBJECT pLogObject = NULL;
PPDHI_LOG_COUNTER pLogCounter = NULL;
PPDHI_LOG_COUNTER pLogInst;
PPDHI_LOG_COUNTER pLogInstHead;
PPERF_DATA_BLOCK pBlock;
PPERF_OBJECT_TYPE pObject;
PPERF_OBJECT_TYPE pParentObject;
PPERF_COUNTER_DEFINITION pCounter;
PPERF_INSTANCE_DEFINITION pInstance;
PPERF_INSTANCE_DEFINITION pParentInstance;
LPWSTR szCounter;
LPWSTR szInstance;
LPWSTR szParent;
DWORD dwInstance;
DWORD dwParent;
BOOL bInstance = FALSE;
DWORD i;
DWORD dwCount;
DWORD dwCounterID;
if (pLogMachine != NULL) {
pLogObject = PdhiFindLogObject(pLogMachine, & pLogMachine->ObjTable, szObjectName, FALSE);
}
if (pLogObject == NULL) {
Status = PDH_INVALID_ARGUMENT;
}
else if (pLogObject->bNeedExpand) {
pCounterTable = pPmLog->pFirstCounterNameTables;
while (pCounterTable != NULL) {
if (lstrcmpiW(pCounterTable->szSystemName, szMachineName) == 0) break;
pCounterTable = pCounterTable->pNext;
}
if (pCounterTable == NULL) {
Status = PDH_INVALID_ARGUMENT;
goto Cleanup;
}
for (i = 0; i < pPmLog->dwLastIndex; i ++) {
pBlock = PdhiDataFromIndex(pPmLog, pPmLog->LogIndexTable[i], szMachineName);
if (pBlock == NULL) continue;
pObject = PdhiFindPerfObject(pBlock, pLogObject->dwObject);
if (pObject == NULL) {
continue;
}
else if (pObject->TotalByteLength <= sizeof(PERF_OBJECT_TYPE)
|| pObject->DefinitionLength <= sizeof(PERF_OBJECT_TYPE)) {
continue;
}
dwCount = pObject->NumCounters;
pCounter = FirstCounter(pObject);
while (pCounter != NULL && dwCount > 0) {
dwCount --;
szCounter = (LPWSTR) PdhiLookupLogPerfNameByIndex(pPmLog,
szMachineName,
pCounterTable->dwLangId,
pCounter->CounterNameTitleIndex);
if (szCounter != NULL) {
pLogCounter = PdhiFindPmCounterInstance(pLogObject,
szCounter,
pCounter->CounterType,
pCounter->DefaultScale,
NULL,
0,
NULL,
pCounter->CounterOffset,
& pCounter->CounterNameTitleIndex,
FALSE,
TRUE);
if (pLogCounter == NULL) {
Status = PDH_MEMORY_ALLOCATION_FAILURE;
break;
}
else if (pCounter->CounterType & PERF_TIMER_100NS) {
pLogCounter->TimeBase = (LONGLONG) 10000000;
}
else if (pCounter->CounterType & PERF_OBJECT_TIMER) {
// then get the time base freq from the object
pLogCounter->TimeBase = pObject->PerfFreq.QuadPart;
}
else { // if (pPerfCounter->CounterType & PERF_TIMER_TICK or other)
pLogCounter->TimeBase = pBlock->PerfFreq.QuadPart;
}
}
pCounter = NextCounter(pObject, pCounter);
}
if (Status != ERROR_SUCCESS) continue;
dwCount = pObject->NumInstances;
bInstance = (dwCount != PERF_NO_INSTANCES) && (dwCount != 0);
if (bInstance) {
for (pLogCounter = pLogObject->InstList; pLogCounter != NULL; pLogCounter = pLogCounter->next) {
pLogCounter->dwCounterType = 0;
}
pInstance = FirstInstance(pObject);
while (pInstance != NULL && dwCount > 0) {
dwCount --;
szInstance = (pInstance->NameOffset != 0) ? (LPWSTR) PointerSeek(pInstance, pInstance->NameOffset)
: NULL;
dwInstance = pInstance->UniqueID;
szParent = NULL;
dwParent = PERF_NO_UNIQUE_ID;
dwCounterID = 0;
if (pInstance->ParentObjectTitleIndex != 0) {
pParentObject = PdhiFindPerfObject(pBlock, pInstance->ParentObjectTitleIndex);
if (pParentObject != NULL && pParentObject->TotalByteLength > sizeof(PERF_OBJECT_TYPE)
&& pParentObject->DefinitionLength > sizeof(PERF_OBJECT_TYPE)) {
pParentInstance = GetInstance(pParentObject, pInstance->ParentObjectInstance);
if (pParentInstance != NULL) {
szParent = (pParentInstance->NameOffset != 0)
? (LPWSTR) PointerSeek(pParentInstance, pParentInstance->NameOffset) : NULL;
dwParent = pParentInstance->UniqueID;
dwCounterID = 1;
}
}
}
if (PdhiFindPmCounterInstance(pLogObject, NULL, 0, 0,
szInstance, dwInstance, szParent, dwParent, & dwCounterID, TRUE, TRUE) == NULL) {
Status = PDH_MEMORY_ALLOCATION_FAILURE;
break;
}
pInstance = NextInstance(pObject, pInstance);
}
}
if (pObject->NumInstances == PERF_NO_INSTANCES) break;
}
pLogInstHead = pLogObject->InstList;
pLogObject->InstList = NULL;
pLogObject->InstTable = NULL;
for (pLogInst = pLogInstHead; pLogInst != NULL; pLogInst = pLogInst->next) {
if (pLogInst->dwInstance != 0 && pLogInst->dwInstance != PERF_NO_UNIQUE_ID) {
PdhiFindPmCounterInstance(pLogObject,
NULL,
0,
0,
pLogInst->szInstance,
pLogInst->dwInstance,
pLogInst->szParent,
pLogInst->dwParent,
& pLogInst->dwCounterID,
TRUE,
TRUE);
}
else {
for (i = 0; i < pLogInst->dwDefaultScale; i ++) {
PdhiFindPmCounterInstance(pLogObject,
NULL,
0,
0,
pLogInst->szInstance,
i,
pLogInst->szParent,
pLogInst->dwParent,
& pLogInst->dwCounterID,
TRUE,
TRUE);
}
}
}
while (pLogInstHead != NULL) {
pLogInst = pLogInstHead;
pLogInstHead = pLogInst->next;
G_FREE(pLogInst);
}
pLogObject->bNeedExpand = FALSE;
}
Cleanup:
return Status;
}
PDH_FUNCTION
PdhiRewindPmLog(
PPDHI_LOG pLog,
PPLAYBACKLOG pPmLog
)
{
PDH_STATUS Status = ERROR_SUCCESS;
if (pPmLog->dwFirstIndex == 0) {
PLOGINDEX pIndex = NULL;
DWORD i;
for (i = 0; i < pPmLog->dwLastIndex; i ++) {
pIndex = pPmLog->LogIndexTable[i];
if ((pIndex->uFlags & LogFileIndexData) != 0) break;
}
if (i < pPmLog->dwLastIndex) {
pPmLog->dwFirstIndex = i;
}
}
if (pPmLog->dwFirstIndex != pPmLog->dwCurrentIndex) {
pLog->dwLastRecordRead = pPmLog->dwFirstIndex;
pPmLog->dwCurrentIndex = pPmLog->dwFirstIndex;
pLog->pLastRecordRead = PointerSeek(pPmLog->pHeader,
pPmLog->LogIndexTable[pPmLog->dwFirstIndex]->lDataOffset);
}
return Status;
}
PDH_FUNCTION
PdhiOpenInputPerfmonLog(
PPDHI_LOG pLog
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
PPLAYBACKLOG pPmPbLog = (PPLAYBACKLOG) pLog->pPerfmonInfo;
pLog->StreamFile = (FILE *) ((DWORD_PTR) (-1));
// map file as a memory array for reading
if (pLog->hMappedLogFile != NULL && pLog->lpMappedFileBase != NULL) {
pLog->dwLastRecordRead = 0;
pLog->pLastRecordRead = NULL;
pLog->pPerfmonInfo = G_ALLOC(sizeof(PLAYBACKLOG));
if (pLog->pPerfmonInfo != NULL) {
pPmPbLog = (PPLAYBACKLOG) pLog->pPerfmonInfo;
// assumes structure was 0-init'd on allocation
pPmPbLog->llFileSize = pLog->llFileSize;
pPmPbLog->szFilePath = pLog->szLogFileName;
pPmPbLog->pHeader = pLog->lpMappedFileBase;
pPmPbLog->iTotalTics = 1;
pPmPbLog->dwFirstIndex = 0;
pPmPbLog->MachineList = NULL;
pPmPbLog->pFirstCounterNameTables = NULL;
pdhStatus = PdhiBuildPmLogIndexTable(pPmPbLog);
if (pdhStatus == ERROR_SUCCESS) {
pdhStatus = PdhiRewindPmLog(pLog, pPmPbLog);
}
}
else {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
}
}
else {
// return PDH Error
pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
}
return pdhStatus;
}
PDH_FUNCTION
PdhiClosePerfmonLog(
PPDHI_LOG pLog,
DWORD dwFlags
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
PPLAYBACKLOG pPlaybackLog = (PPLAYBACKLOG) pLog->pPerfmonInfo;
DBG_UNREFERENCED_PARAMETER(dwFlags);
if (pPlaybackLog != NULL) {
G_FREE(pPlaybackLog->LogIndexTable);
PdhiFreeLogMachineTable(& pPlaybackLog->MachineList);
PdhiFreePmMachineList(pPlaybackLog);
G_FREE(pLog->pPerfmonInfo);
pLog->pPerfmonInfo = NULL;
}
return pdhStatus;
}
PDH_FUNCTION
PdhiGetPerfmonLogCounterInfo(
PPDHI_LOG pLog,
PPDHI_COUNTER pCounter
)
{
PDH_STATUS pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
PPLAYBACKLOG pPlaybackLog = (PPLAYBACKLOG) pLog->pPerfmonInfo;
PPDHI_LOG_MACHINE pLogMachine = NULL;
PPDHI_LOG_OBJECT pLogObject = NULL;
PPDHI_LOG_COUNTER pLogCounter = NULL;
PPDHI_LOG_COUNTER pLogInstance = NULL;
DWORD dwCounter;
PPERF_DATA_BLOCK pPerfData = NULL;
PPERF_OBJECT_TYPE pObjectDef;
PPERF_COUNTER_DEFINITION pPerfCounter;
PPERF_INSTANCE_DEFINITION pInstanceDef;
DWORD dwObjectId = 0;
LOGPOSITION LogPosition;
LOGINDEX * pLogIndex;
LPWSTR * pCounterNames = NULL;
DWORD dwLastCounterNameIndex = 0;
BOOL bObjectNumber = FALSE;
if (pPlaybackLog != NULL) {
pdhStatus = PdhiCachePmLogHeader(pPlaybackLog);
if (pdhStatus == ERROR_SUCCESS) {
pdhStatus = PdhiCachePmLogObject(pPlaybackLog,
pCounter->pCounterPath->szMachineName,
pCounter->pCounterPath->szObjectName);
}
}
if (pdhStatus == ERROR_SUCCESS) {
pLogMachine = PdhiFindLogMachine(& pPlaybackLog->MachineList, pCounter->pCounterPath->szMachineName, FALSE);
pCounter->pThisRawItemList = (LPVOID) pLogMachine;
if (pLogMachine != NULL) {
pLogObject = PdhiFindLogObject(
pLogMachine, & pLogMachine->ObjTable, pCounter->pCounterPath->szObjectName, FALSE);
pCounter->pLastRawItemList = (LPVOID) pLogObject;
if (pLogObject == NULL) {
pdhStatus = PDH_CSTATUS_NO_OBJECT;
}
}
else {
pdhStatus = PDH_CSTATUS_NO_MACHINE;
}
}
if (pdhStatus == ERROR_SUCCESS) {
pLogCounter = PdhiFindPmCounterInstance(pLogObject,
pCounter->pCounterPath->szCounterName,
0,
0,
NULL,
0,
NULL,
0,
& dwCounter,
FALSE,
FALSE);
pCounter->pThisObject = (LPVOID) pLogCounter;
if (pCounter->pCounterPath->szInstanceName != NULL) {
pLogInstance = PdhiFindPmCounterInstance(pLogObject,
NULL,
0,
0,
pCounter->pCounterPath->szInstanceName,
pCounter->pCounterPath->dwIndex,
pCounter->pCounterPath->szParentName,
0,
& dwCounter,
TRUE,
FALSE);
pCounter->pLastObject = (LPVOID) pLogInstance;
}
}
if (pLogCounter != NULL) {
if (pCounter->pCounterPath->szInstanceName != NULL) {
if (pLogInstance == NULL) {
pdhStatus = PDH_CSTATUS_NO_INSTANCE;
}
}
pCounter->plCounterInfo.dwObjectId = pLogObject->dwObject;
if (pLogInstance) {
pCounter->plCounterInfo.lInstanceId = (pLogInstance->szInstance == NULL)
? pLogInstance->dwInstance : PERF_NO_UNIQUE_ID;
pCounter->plCounterInfo.dwParentObjectId = pLogInstance->dwParent;
}
else {
pCounter->plCounterInfo.lInstanceId = PERF_NO_UNIQUE_ID;
pCounter->plCounterInfo.dwParentObjectId = PERF_NO_UNIQUE_ID;
}
pCounter->plCounterInfo.szInstanceName = pCounter->pCounterPath->szInstanceName;
pCounter->plCounterInfo.szParentInstanceName = pCounter->pCounterPath->szParentName;
pCounter->plCounterInfo.dwCounterId = pLogCounter->dwCounterID;
pCounter->plCounterInfo.dwCounterType = pLogCounter->dwCounterType;
pCounter->plCounterInfo.dwCounterSize = pLogCounter->dwInstance;
pCounter->plCounterInfo.lDefaultScale = pLogCounter->dwDefaultScale;
pCounter->TimeBase = pLogCounter->TimeBase;
}
else {
pdhStatus = PDH_CSTATUS_NO_COUNTER;
}
return pdhStatus;
}
PDH_FUNCTION
PdhiEnumMachinesFromPerfmonLog(
PPDHI_LOG pLog,
LPVOID pBuffer,
LPDWORD pcchBufferSize,
BOOL bUnicodeDest
)
{
PDH_STATUS pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
PPLAYBACKLOG pPlaybackLog = (PPLAYBACKLOG) pLog->pPerfmonInfo;
if (pPlaybackLog != NULL) {
pdhStatus = PdhiCachePmLogHeader(pPlaybackLog);
if (pdhStatus == ERROR_SUCCESS) {
pdhStatus = PdhiEnumCachedMachines(pPlaybackLog->MachineList, pBuffer, pcchBufferSize, bUnicodeDest);
}
}
return pdhStatus;
}
PDH_FUNCTION
PdhiEnumObjectsFromPerfmonLog(
PPDHI_LOG pLog,
LPCWSTR lpszSystemName,
LPVOID pBuffer,
LPDWORD pcchBufferSize,
DWORD dwDetailLevel,
BOOL bUnicodeDest
)
{
PDH_STATUS pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
PPLAYBACKLOG pPlaybackLog = (PPLAYBACKLOG) pLog->pPerfmonInfo;
if (pPlaybackLog != NULL) {
pdhStatus = PdhiCachePmLogHeader(pPlaybackLog);
if (pdhStatus == ERROR_SUCCESS) {
pdhStatus = PdhiEnumCachedObjects(
pPlaybackLog->MachineList, lpszSystemName, pBuffer, pcchBufferSize, dwDetailLevel, bUnicodeDest);
}
}
return pdhStatus;
}
PDH_FUNCTION
PdhiEnumObjectItemsFromPerfmonLog(
PPDHI_LOG pLog,
LPCWSTR szMachineName,
LPCWSTR szObjectName,
PDHI_COUNTER_TABLE CounterTable,
DWORD dwDetailLevel,
DWORD dwFlags
)
{
PDH_STATUS pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
PPLAYBACKLOG pPlaybackLog = (PPLAYBACKLOG) pLog->pPerfmonInfo;
HRESULT hr;
DBG_UNREFERENCED_PARAMETER(dwFlags);
DBG_UNREFERENCED_PARAMETER(dwDetailLevel);
if (pPlaybackLog != NULL) {
pdhStatus = PdhiCachePmLogHeader(pPlaybackLog);
if (pdhStatus == ERROR_SUCCESS) {
pdhStatus = PdhiCachePmLogObject(pPlaybackLog, (LPWSTR) szMachineName, (LPWSTR) szObjectName);
}
}
if (pdhStatus == ERROR_SUCCESS) {
PPDHI_LOG_MACHINE pMachine = NULL;
PPDHI_LOG_OBJECT pObject = NULL;
PPDHI_LOG_COUNTER pCtr = NULL;
PPDHI_LOG_COUNTER pInst = NULL;
PPDHI_INST_LIST pFirstInstList = NULL;
PPDHI_INST_LIST pInstList = NULL;
PPDHI_INSTANCE pInstance = NULL;
LONG nCounterCount = 0;
LONG nInstanceCount = 0;
pMachine = PdhiFindLogMachine(& pPlaybackLog->MachineList, (LPWSTR) szMachineName, FALSE);
if (pMachine == NULL) {
pdhStatus = PDH_CSTATUS_NO_MACHINE;
}
else {
pObject = PdhiFindLogObject(pMachine, & (pMachine->ObjTable), (LPWSTR) szObjectName, FALSE);
if (pObject == NULL) {
pdhStatus = PDH_CSTATUS_NO_OBJECT;
}
}
if (pdhStatus == ERROR_SUCCESS) {
for (pCtr = pObject->CtrList; pCtr != NULL; pCtr = pCtr->next) {
pdhStatus = PdhiFindCounterInstList(CounterTable, pCtr->szCounter, & pInstList);
if (pdhStatus != ERROR_SUCCESS) {
continue;
}
else {
nCounterCount ++;
if (pFirstInstList == NULL) {
pFirstInstList = pInstList;
}
}
}
if (pFirstInstList != NULL) {
pInst = pObject->InstList;
if (pInst != NULL && pInst != PDH_INVALID_POINTER) {
LPWSTR szFullInstance = G_ALLOC((PDH_MAX_INSTANCE_NAME + 1) * sizeof(WCHAR));
if (szFullInstance != NULL) {
while (pInst != NULL) {
ZeroMemory(szFullInstance, (PDH_MAX_INSTANCE_NAME + 1) * sizeof(WCHAR));
if (pInst->szInstance != NULL) {
if (pInst->dwCounterID != 0) {
if (pInst->szParent != NULL) {
if (pInst->dwInstance != 0 && pInst->dwInstance != PERF_NO_UNIQUE_ID) {
hr = StringCchPrintfW(szFullInstance,
PDH_MAX_INSTANCE_NAME, L"%ws%ws%ws#%u",
pInst->szParent, cszSlash, pInst->szInstance, pInst->dwInstance);
}
else {
hr = StringCchPrintfW(szFullInstance,
PDH_MAX_INSTANCE_NAME, L"%ws%ws%ws",
pInst->szParent, cszSlash, pInst->szInstance);
}
}
else {
if (pInst->dwInstance != 0 && pInst->dwInstance != PERF_NO_UNIQUE_ID) {
hr = StringCchPrintfW(szFullInstance,
PDH_MAX_INSTANCE_NAME, L"%u%ws%ws#%u",
pInst->dwParent, cszSlash, pInst->szInstance, pInst->dwInstance);
}
else {
hr = StringCchPrintfW(szFullInstance,
PDH_MAX_INSTANCE_NAME, L"%u%ws%ws",
pInst->dwParent, cszSlash, pInst->szInstance);
}
}
}
else if (pInst->dwInstance != 0 && pInst->dwInstance != PERF_NO_UNIQUE_ID) {
hr = StringCchPrintfW(szFullInstance, PDH_MAX_INSTANCE_NAME, L"%ws#%u",
pInst->szInstance, pInst->dwInstance);
}
else {
hr = StringCchCopyW(szFullInstance, PDH_MAX_INSTANCE_NAME, pInst->szInstance);
}
}
else if (pInst->dwCounterID != 0) {
if (pInst->szParent != NULL) {
hr = StringCchPrintfW(szFullInstance, PDH_MAX_INSTANCE_NAME, L"%ws%ws%u",
pInst->szParent, cszSlash, pInst->dwInstance);
}
else {
hr = StringCchPrintfW(szFullInstance, PDH_MAX_INSTANCE_NAME, L"%u%ws%u",
pInst->dwParent, cszSlash, pInst->dwInstance);
}
}
else {
hr = StringCchPrintfW(szFullInstance, PDH_MAX_INSTANCE_NAME, L"%u",
pInst->dwInstance);
}
// ignore checkin hr return, we intend to truncate string to PDH_MAX_INSTANCE_NAME
pdhStatus = PdhiFindInstance(& pFirstInstList->InstList, szFullInstance, TRUE, & pInstance);
if (pdhStatus == ERROR_SUCCESS) {
nInstanceCount ++;
}
pInst = pInst->next;
}
}
else {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
}
}
}
if (nCounterCount == 0 && nInstanceCount == 0) {
if (pdhStatus == ERROR_SUCCESS) {
pdhStatus = PDH_CSTATUS_NO_OBJECT;
}
}
else if (pdhStatus != PDH_MORE_DATA) {
// then the routine was successful. Errors that occurred
// while scanning will be ignored as long as at least
// one entry was successfully read
pdhStatus = ERROR_SUCCESS;
}
}
}
return pdhStatus;
}
PDH_FUNCTION
PdhiGetMatchingPerfmonLogRecord(
PPDHI_LOG pLog,
LONGLONG * pStartTime,
LPDWORD pdwIndex
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
PPLAYBACKLOG pPlaybackLog = (PPLAYBACKLOG) pLog->pPerfmonInfo;
DWORD dwThisIndex = 0;
DWORD dwLastIndex = 0;
LONGLONG llThisTime = 0;
PPERF_DATA_BLOCK pPerfData;
FILETIME ftGMT;
if (pPlaybackLog == NULL) {
pdhStatus = PDH_LOG_FILE_OPEN_ERROR; // log is invalid
}
else {
dwLastIndex = pPlaybackLog->dwFirstIndex;
for (dwThisIndex = pPlaybackLog->dwFirstIndex; dwThisIndex < pPlaybackLog->dwLastIndex; dwThisIndex ++) {
pPerfData = (PPERF_DATA_BLOCK) PointerSeek(
pPlaybackLog->pHeader, pPlaybackLog->LogIndexTable[dwThisIndex]->lDataOffset);
if (pPerfData != NULL) {
SystemTimeToFileTime(& pPerfData->SystemTime, & ftGMT);
FileTimeToLocalFileTime(& ftGMT, (FILETIME *) & llThisTime);
if (llThisTime == * pStartTime) {
// record found
break;
}
else if (llThisTime > * pStartTime) {
// go back one
dwThisIndex = dwLastIndex;
break;
}
else {
dwLastIndex = dwThisIndex;
// go to the next one
}
}
else {
dwLastIndex = dwThisIndex;
// go to the next one
}
}
if (dwThisIndex == pPlaybackLog->dwLastIndex) {
// then there's no more records in the log
pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
}
}
if (pdhStatus == ERROR_SUCCESS) {
if (pdwIndex != NULL) * pdwIndex = dwThisIndex;
if (pLog->dwLastRecordRead != dwThisIndex) {
pLog->dwLastRecordRead = dwThisIndex;
pPlaybackLog->dwCurrentIndex = dwThisIndex;
pLog->pLastRecordRead = PointerSeek(pPlaybackLog->pHeader,
pPlaybackLog->LogIndexTable[dwThisIndex]->lDataOffset);
}
}
return pdhStatus;
}
DWORD
PdhiGetPmBaseCounterOffset(
PPDHI_LOG_COUNTER pCounter,
PPERF_OBJECT_TYPE pPerfObject
)
{
DWORD dwReturn = pCounter->dwInstance;
if (pCounter->dwInstance == 0) {
PPERF_COUNTER_DEFINITION pPerfCounter = FirstCounter(pPerfObject);
DWORD dwCounter = pPerfObject->NumCounters;
while (pPerfCounter != NULL && dwCounter > 0) {
dwCounter --;
if (pPerfCounter->CounterNameTitleIndex == pCounter->dwCounterID) {
pPerfCounter = NextCounter(pPerfObject, pPerfCounter);
if (pPerfCounter == NULL) break;
if ((pPerfCounter->CounterType & PERF_COUNTER_BASE) != 0) {
dwReturn = pPerfCounter->CounterOffset;
break;
}
}
pPerfCounter = NextCounter(pPerfObject, pPerfCounter);
}
pCounter->dwInstance = dwReturn;
}
return dwReturn;
}
PDH_FUNCTION
PdhiGetCounterValueFromPerfmonLog(
PPDHI_LOG pLog,
DWORD dwIndex,
PPDHI_COUNTER pCounter,
PPDH_RAW_COUNTER pValue
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
PPLAYBACKLOG pPlaybackLog = (PPLAYBACKLOG) pLog->pPerfmonInfo;
PLOGINDEX pIndex = NULL;
PPERF_DATA_BLOCK pPerfData = NULL;
PPERF_OBJECT_TYPE pPerfObject = NULL;
PPERF_INSTANCE_DEFINITION pPerfInst = NULL;
PPERF_COUNTER_BLOCK pCtrBlock = NULL;
LPVOID pEndGuard;
PPDHI_LOG_MACHINE pLogMachine = (PPDHI_LOG_MACHINE) pCounter->pThisRawItemList;
PPDHI_LOG_OBJECT pLogObject = (PPDHI_LOG_OBJECT) pCounter->pLastRawItemList;
PPDHI_LOG_COUNTER pLogCounter = (PPDHI_LOG_COUNTER) pCounter->pThisObject;
PPDHI_LOG_COUNTER pLogInstance = (PPDHI_LOG_COUNTER) pCounter->pLastObject;
BOOL bReturn;
DWORD LocalCType;
DWORD * pdwData;
UNALIGNED LONGLONG * pllData;
LPVOID pData = NULL;
FILETIME ftGMT;
if (pPlaybackLog == NULL) {
pdhStatus = PDH_LOG_FILE_OPEN_ERROR; // log is invalid
}
else if (dwIndex < pPlaybackLog->dwFirstIndex) {
// invalid dwIndex value
pdhStatus = PDH_INVALID_ARGUMENT;
}
else if (dwIndex >= pPlaybackLog->dwLastIndex) {
pdhStatus = PDH_NO_MORE_DATA;
}
else if (pLogMachine == NULL || pLogObject == NULL || pLogCounter == NULL) {
pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
}
else {
if (pLog->dwLastRecordRead != dwIndex) {
pLog->dwLastRecordRead = dwIndex;
pPlaybackLog->dwCurrentIndex = dwIndex;
pLog->pLastRecordRead = PointerSeek(pPlaybackLog->pHeader,
pPlaybackLog->LogIndexTable[dwIndex]->lDataOffset);
}
pIndex = pPlaybackLog->LogIndexTable[dwIndex];
}
if (pdhStatus == ERROR_SUCCESS) {
// find a matching system...
if (pLogMachine->pBlock != NULL && pLogMachine->dwIndex == dwIndex) {
pPerfData = pLogMachine->pBlock;
}
else {
pPerfData = PdhiDataFromIndex(pPlaybackLog, pIndex, pCounter->pCounterPath->szMachineName);
pLogMachine->pBlock = pPerfData;
pLogMachine->dwIndex = dwIndex;
}
if (pPerfData == NULL) {
pdhStatus = PDH_CSTATUS_NO_MACHINE;
pLogObject->pObjData = NULL;
pLogObject->dwIndex = dwIndex;
}
else if (pLogObject->pObjData != NULL && pLogObject->dwIndex == dwIndex) {
pPerfObject = pLogObject->pObjData;
}
else {
pEndGuard = PointerSeek(pPerfData, pPerfData->TotalByteLength);
pPerfObject = PdhiFindPerfObject(pPerfData, pLogObject->dwObject);
pLogObject->dwIndex = dwIndex;
if (pPerfObject != NULL && ((LPVOID) pPerfObject) < pEndGuard) {
pLogObject->pObjData = pPerfObject;
}
else {
pLogObject->pObjData = NULL;
pdhStatus = PDH_CSTATUS_NO_OBJECT;
}
}
}
if (pdhStatus == ERROR_SUCCESS) {
pEndGuard = PointerSeek(pPerfObject, pPerfObject->TotalByteLength);
if (pPerfObject->NumInstances == PERF_NO_INSTANCES) {
pCtrBlock = (PPERF_COUNTER_BLOCK) PointerSeek(pPerfObject, pPerfObject->DefinitionLength);
if (pCtrBlock != NULL && ((LPVOID) pCtrBlock) < pEndGuard) {
pData = PointerSeek(pCtrBlock, pLogCounter->dwParent);
if (pData >= pEndGuard) pData = NULL;
}
}
else if (pLogInstance != NULL) {
if (pLogInstance->szCounter != NULL && pLogInstance->dwCounterType == dwIndex) {
pCtrBlock = (PPERF_COUNTER_BLOCK) pLogInstance->szCounter;
}
else {
if (pCounter->plCounterInfo.lInstanceId == PERF_NO_UNIQUE_ID
&& pCounter->pCounterPath->szInstanceName != NULL) {
pPerfInst = GetInstanceByName(pPerfData,
pPerfObject,
pCounter->pCounterPath->szInstanceName,
pCounter->pCounterPath->szParentName,
pCounter->pCounterPath->dwIndex);
if (pPerfInst == NULL && pCounter->pCounterPath->szInstanceName[0] >= L'0'
&& pCounter->pCounterPath->szInstanceName[0] <= L'9') {
LONG lInstanceId = (LONG) _wtoi(pCounter->pCounterPath->szInstanceName);
pPerfInst = GetInstanceByUniqueId(pPerfObject, lInstanceId);
}
}
else {
pPerfInst = GetInstanceByUniqueId(pPerfObject, pCounter->plCounterInfo.lInstanceId);
}
if (((LPVOID) pPerfInst) >= pEndGuard) pPerfInst = NULL;
if (pPerfInst != NULL) {
pCtrBlock = (PPERF_COUNTER_BLOCK) PointerSeek(pPerfInst, pPerfInst->ByteLength);
if (((LPVOID) pCtrBlock) >= pEndGuard) pCtrBlock = NULL;
}
pLogInstance->szCounter = (LPVOID) pCtrBlock;
pLogInstance->dwCounterType = dwIndex;
}
if (pCtrBlock != NULL) {
pData = PointerSeek(pCtrBlock, pLogCounter->dwParent);
if (pData >= pEndGuard) pData = NULL;
}
else {
pdhStatus = PDH_CSTATUS_NO_INSTANCE;
}
}
else {
pdhStatus = PDH_CSTATUS_NO_INSTANCE;
}
}
if (pdhStatus == ERROR_SUCCESS) {
if (pData == NULL) {
pdhStatus = PDH_INVALID_DATA;
}
else {
// assume success
bReturn = TRUE;
// convert system time in GMT to Local File time
SystemTimeToFileTime(& pPerfData->SystemTime, & ftGMT);
FileTimeToLocalFileTime(& ftGMT, & pValue->TimeStamp);
pValue->MultiCount = 1; // unless changed
// load counter value based on counter type
LocalCType = pCounter->plCounterInfo.dwCounterType;
switch (LocalCType) {
//
// these counter types are loaded as:
// Numerator = Counter data from perf data block
// Denominator = Perf Time from perf data block
// (the time base is the PerfFreq)
//
case PERF_COUNTER_COUNTER:
case PERF_COUNTER_QUEUELEN_TYPE:
case PERF_SAMPLE_COUNTER:
pValue->FirstValue = (LONGLONG) (* (DWORD *) pData);
pValue->SecondValue = pPerfData->PerfTime.QuadPart;
break;
case PERF_OBJ_TIME_TIMER:
pValue->FirstValue = (LONGLONG) (* (DWORD *) pData);
pValue->SecondValue = pPerfObject->PerfTime.QuadPart;
break;
case PERF_COUNTER_100NS_QUEUELEN_TYPE:
pllData = (UNALIGNED LONGLONG *) pData;
pValue->FirstValue = * pllData;
pValue->SecondValue = pPerfData->PerfTime100nSec.QuadPart;
break;
case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
pllData = (UNALIGNED LONGLONG *) pData;
pValue->FirstValue = * pllData;
pValue->SecondValue = pPerfObject->PerfTime.QuadPart;
break;
case PERF_COUNTER_TIMER:
case PERF_COUNTER_TIMER_INV:
case PERF_COUNTER_BULK_COUNT:
case PERF_COUNTER_MULTI_TIMER:
case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
pllData = (UNALIGNED LONGLONG *) pData;
pValue->FirstValue = * pllData;
pValue->SecondValue = pPerfData->PerfTime.QuadPart;
if ((LocalCType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
pValue->MultiCount = (DWORD) * ++ pllData;
}
break;
//
// These counters do not use any time reference
//
case PERF_COUNTER_RAWCOUNT:
case PERF_COUNTER_RAWCOUNT_HEX:
pValue->FirstValue = (LONGLONG) (* (DWORD *) pData);
pValue->SecondValue = 0;
break;
case PERF_COUNTER_LARGE_RAWCOUNT:
case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
pValue->FirstValue = * (LONGLONG *) pData;
pValue->SecondValue = 0;
break;
//
// These counters use the 100 Ns time base in thier calculation
//
case PERF_100NSEC_TIMER:
case PERF_100NSEC_TIMER_INV:
case PERF_100NSEC_MULTI_TIMER:
case PERF_100NSEC_MULTI_TIMER_INV:
pllData = (UNALIGNED LONGLONG *) pData;
pValue->FirstValue = * pllData;
pValue->SecondValue = pPerfData->PerfTime100nSec.QuadPart;
if ((LocalCType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
++ pllData;
pValue->MultiCount = * (DWORD *) pllData;
}
break;
//
// These counters use two data points, the one pointed to by
// pData and the one immediately after
//
case PERF_SAMPLE_FRACTION:
case PERF_RAW_FRACTION:
pdwData = (DWORD *) pData;
pValue->FirstValue = (LONGLONG) (* pdwData);
// find the pointer to the base value in the structure
PdhiGetPmBaseCounterOffset(pLogCounter, pPerfObject);
if (pLogCounter->dwInstance > 0) {
pData = PointerSeek(pCtrBlock, pLogCounter->dwInstance);
pdwData = (DWORD *) pData;
pValue->SecondValue = (LONGLONG) (* pdwData);
}
else {
// unable to locate base value
pValue->SecondValue = 0;
bReturn = FALSE;
}
break;
case PERF_PRECISION_SYSTEM_TIMER:
case PERF_PRECISION_100NS_TIMER:
case PERF_PRECISION_OBJECT_TIMER:
pllData = (LONGLONG *) pData;
pValue->FirstValue = * pllData;
// find the pointer to the base value in the structure
PdhiGetPmBaseCounterOffset(pLogCounter, pPerfObject);
if (pLogCounter->dwInstance > 0) {
pData = PointerSeek(pCtrBlock, pLogCounter->dwInstance);
pllData = (LONGLONG *) pData;
pValue->SecondValue = * pllData;
}
else {
// unable to locate base value
pValue->SecondValue = 0;
bReturn = FALSE;
}
break;
case PERF_AVERAGE_TIMER:
case PERF_AVERAGE_BULK:
// counter (numerator) is a LONGLONG, while the
// denominator is just a DWORD
pllData = (UNALIGNED LONGLONG *) pData;
pValue->FirstValue = * pllData;
PdhiGetPmBaseCounterOffset(pLogCounter, pPerfObject);
if (pLogCounter->dwInstance > 0) {
pData = PointerSeek(pCtrBlock, pLogCounter->dwInstance);
pdwData = (DWORD *) pData;
pValue->SecondValue = * pdwData;
}
else {
pValue->SecondValue = 0;
bReturn = FALSE;
}
break;
//
// These counters are used as the part of another counter
// and as such should not be used, but in case they are
// they'll be handled here.
//
case PERF_SAMPLE_BASE:
case PERF_AVERAGE_BASE:
case PERF_COUNTER_MULTI_BASE:
case PERF_RAW_BASE:
pValue->FirstValue = 0;
pValue->SecondValue = 0;
break;
case PERF_ELAPSED_TIME:
// this counter type needs the object perf data as well
pValue->SecondValue = pPerfObject->PerfTime.QuadPart;
pCounter->TimeBase = pPerfObject->PerfFreq.QuadPart;
pllData = (UNALIGNED LONGLONG *) pData;
pValue->FirstValue = *pllData;
break;
//
// These counters are not supported by this function (yet)
//
case PERF_COUNTER_TEXT:
case PERF_COUNTER_NODATA:
case PERF_COUNTER_HISTOGRAM_TYPE:
pValue->FirstValue = 0;
pValue->SecondValue = 0;
break;
default:
// an unidentified counter was returned so
pValue->FirstValue = 0;
pValue->SecondValue = 0;
bReturn = FALSE;
break;
}
pValue->CStatus = PDH_CSTATUS_VALID_DATA;
}
}
return pdhStatus;
}
PDH_FUNCTION
PdhiGetTimeRangeFromPerfmonLog(
PPDHI_LOG pLog,
LPDWORD pdwNumEntries,
PPDH_TIME_INFO pInfo,
LPDWORD pdwBufferSize
)
/*++
the first entry in the buffer returned is the total time range covered
in the file, if there are multiple time blocks in the log file, then
subsequent entries will identify each segment in the file.
--*/
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
PPLAYBACKLOG pPlaybackLog = (PLAYBACKLOG *) pLog->pPerfmonInfo;
PDH_TIME_INFO LocalTimeInfo = {0,0,0};
PPERF_DATA_BLOCK pPerfData;
FILETIME ftGMT;
if (pPlaybackLog == NULL) {
pdhStatus = PDH_INVALID_HANDLE; // log is invalid
}
else {
pPerfData = (PPERF_DATA_BLOCK) PointerSeek(
pPlaybackLog->pHeader, pPlaybackLog->LogIndexTable[pPlaybackLog->dwFirstIndex]->lDataOffset);
if (pPerfData != NULL) {
SystemTimeToFileTime(& pPerfData->SystemTime, & ftGMT);
FileTimeToLocalFileTime(& ftGMT, (FILETIME *) & LocalTimeInfo.StartTime);
}
else {
pdhStatus = PDH_NO_DATA;
}
pPerfData = (PPERF_DATA_BLOCK) PointerSeek(
pPlaybackLog->pHeader, pPlaybackLog->LogIndexTable[pPlaybackLog->dwLastIndex - 1]->lDataOffset);
if (pPerfData != NULL) {
SystemTimeToFileTime(& pPerfData->SystemTime, & ftGMT);
FileTimeToLocalFileTime(& ftGMT, (FILETIME *) & LocalTimeInfo.EndTime);
}
else {
pdhStatus = PDH_NO_DATA;
}
}
if (pdhStatus == ERROR_SUCCESS) {
LocalTimeInfo.SampleCount = pPlaybackLog->dwLastIndex - pPlaybackLog->dwFirstIndex;
if (pInfo != NULL && * pdwBufferSize >= sizeof(PDH_TIME_INFO)) {
* pdwNumEntries = 1;
* pInfo = LocalTimeInfo;
* pdwBufferSize = sizeof(PDH_TIME_INFO);
pdhStatus = ERROR_SUCCESS;
}
else {
* pdwBufferSize = sizeof(PDH_TIME_INFO);
pdhStatus = PDH_MORE_DATA;
}
}
return pdhStatus;
}
PDH_FUNCTION
PdhiReadRawPerfmonLogRecord(
PPDHI_LOG pLog,
FILETIME * ftRecord,
PPDH_RAW_LOG_RECORD pBuffer,
LPDWORD pdwBufferLength
)
{
PDH_STATUS pdhStatus = PDH_NOT_IMPLEMENTED;
DBG_UNREFERENCED_PARAMETER(pLog);
DBG_UNREFERENCED_PARAMETER(ftRecord);
DBG_UNREFERENCED_PARAMETER(pBuffer);
DBG_UNREFERENCED_PARAMETER(pdwBufferLength);
return pdhStatus;
}