195 lines
5.5 KiB
C
195 lines
5.5 KiB
C
/*
|
|
* Process Hacker Plugins -
|
|
* Performance Monitor Plugin
|
|
*
|
|
* Copyright (C) 2016 dmex
|
|
*
|
|
* This file is part of Process Hacker.
|
|
*
|
|
* Process Hacker is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Process Hacker is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "perfmon.h"
|
|
|
|
VOID PerfMonEntryDeleteProcedure(
|
|
_In_ PVOID Object,
|
|
_In_ ULONG Flags
|
|
)
|
|
{
|
|
PPERF_COUNTER_ENTRY entry = Object;
|
|
|
|
PhAcquireQueuedLockExclusive(&PerfCounterListLock);
|
|
PhRemoveItemList(PerfCounterList, PhFindItemList(PerfCounterList, entry));
|
|
PhReleaseQueuedLockExclusive(&PerfCounterListLock);
|
|
|
|
DeletePerfCounterId(&entry->Id);
|
|
PhDeleteCircularBuffer_ULONG64(&entry->HistoryBuffer);
|
|
|
|
if (entry->PerfQueryHandle)
|
|
{
|
|
PdhCloseQuery(entry->PerfQueryHandle);
|
|
entry->PerfQueryHandle = NULL;
|
|
}
|
|
|
|
if (entry->PerfCounterInfo)
|
|
{
|
|
PhFree(entry->PerfCounterInfo);
|
|
entry->PerfCounterInfo = NULL;
|
|
}
|
|
|
|
//PhDereferenceObject(entry);
|
|
}
|
|
|
|
VOID PerfMonInitialize(
|
|
VOID
|
|
)
|
|
{
|
|
PerfCounterList = PhCreateList(1);
|
|
PerfCounterEntryType = PhCreateObjectType(L"PerfMonEntry", 0, PerfMonEntryDeleteProcedure);
|
|
}
|
|
|
|
VOID PerfMonUpdate(
|
|
VOID
|
|
)
|
|
{
|
|
static ULONG runCount = 0; // MUST keep in sync with runCount in process provider
|
|
|
|
PhAcquireQueuedLockShared(&PerfCounterListLock);
|
|
|
|
for (ULONG i = 0; i < PerfCounterList->Count; i++)
|
|
{
|
|
PPERF_COUNTER_ENTRY entry;
|
|
ULONG counterType = 0;
|
|
PDH_FMT_COUNTERVALUE displayValue = { 0 };
|
|
|
|
entry = PhReferenceObjectSafe(PerfCounterList->Items[i]);
|
|
|
|
if (!entry)
|
|
continue;
|
|
|
|
if (entry->HaveFirstSample)
|
|
{
|
|
if (!entry->PerfQueryHandle)
|
|
{
|
|
if (PdhOpenQuery(NULL, 0, &entry->PerfQueryHandle) == ERROR_SUCCESS)
|
|
{
|
|
if (PdhAddCounter(entry->PerfQueryHandle, PhGetString(entry->Id.PerfCounterPath), 0, &entry->PerfCounterHandle) == ERROR_SUCCESS)
|
|
{
|
|
ULONG counterLength;
|
|
|
|
if (PdhGetCounterInfo(entry->PerfCounterHandle, TRUE, &counterLength, NULL) == PDH_MORE_DATA)
|
|
{
|
|
entry->PerfCounterInfo = PhAllocate(counterLength);
|
|
memset(entry->PerfCounterInfo, 0, counterLength);
|
|
}
|
|
|
|
if (PdhGetCounterInfo(entry->PerfCounterHandle, TRUE, &counterLength, entry->PerfCounterInfo) == ERROR_SUCCESS)
|
|
{
|
|
|
|
}
|
|
|
|
OutputDebugString(L"");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update the counter data
|
|
PdhCollectQueryData(entry->PerfQueryHandle);
|
|
|
|
//PdhSetCounterScaleFactor(entry->PerfCounterHandle, PDH_MAX_SCALE);
|
|
//PdhGetRawCounterValue(entry->PerfCounterHandle, 0, &rawValue);
|
|
|
|
if (PdhGetFormattedCounterValue(
|
|
entry->PerfCounterHandle,
|
|
PDH_FMT_LARGE | PDH_FMT_NOSCALE | PDH_FMT_NOCAP100,
|
|
&counterType,
|
|
&displayValue
|
|
) == ERROR_SUCCESS && counterType == PERF_COUNTER_COUNTER)
|
|
{
|
|
PhUpdateDelta(&entry->HistoryDelta, displayValue.largeValue);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PhInitializeDelta(&entry->HistoryDelta); // The first sample must be zero
|
|
|
|
entry->HaveFirstSample = TRUE;
|
|
}
|
|
|
|
if (runCount != 0)
|
|
{
|
|
PhAddItemCircularBuffer_ULONG64(&entry->HistoryBuffer, entry->HistoryDelta.Value);
|
|
}
|
|
|
|
PhDereferenceObjectDeferDelete(entry);
|
|
}
|
|
|
|
PhReleaseQueuedLockShared(&PerfCounterListLock);
|
|
|
|
runCount++;
|
|
}
|
|
|
|
VOID InitializePerfCounterId(
|
|
_Out_ PPERF_COUNTER_ID Id,
|
|
_In_ PPH_STRING PerfCounterPath
|
|
)
|
|
{
|
|
PhSetReference(&Id->PerfCounterPath, PerfCounterPath);
|
|
}
|
|
|
|
VOID CopyPerfCounterId(
|
|
_Out_ PPERF_COUNTER_ID Destination,
|
|
_In_ PPERF_COUNTER_ID Source
|
|
)
|
|
{
|
|
InitializePerfCounterId(Destination, Source->PerfCounterPath);
|
|
}
|
|
|
|
VOID DeletePerfCounterId(
|
|
_Inout_ PPERF_COUNTER_ID Id
|
|
)
|
|
{
|
|
PhClearReference(&Id->PerfCounterPath);
|
|
}
|
|
|
|
BOOLEAN EquivalentPerfCounterId(
|
|
_In_ PPERF_COUNTER_ID Id1,
|
|
_In_ PPERF_COUNTER_ID Id2
|
|
)
|
|
{
|
|
if (!Id1 || !Id2)
|
|
return FALSE;
|
|
|
|
return PhEqualString(Id1->PerfCounterPath, Id2->PerfCounterPath, TRUE);
|
|
}
|
|
|
|
PPERF_COUNTER_ENTRY CreatePerfCounterEntry(
|
|
_In_ PPERF_COUNTER_ID Id
|
|
)
|
|
{
|
|
PPERF_COUNTER_ENTRY entry;
|
|
|
|
entry = PhCreateObject(sizeof(PERF_COUNTER_ENTRY), PerfCounterEntryType);
|
|
memset(entry, 0, sizeof(PERF_COUNTER_ENTRY));
|
|
|
|
CopyPerfCounterId(&entry->Id, Id);
|
|
|
|
PhInitializeCircularBuffer_ULONG64(&entry->HistoryBuffer, PhGetIntegerSetting(L"SampleCount"));
|
|
|
|
PhAcquireQueuedLockExclusive(&PerfCounterListLock);
|
|
PhAddItemList(PerfCounterList, entry);
|
|
PhReleaseQueuedLockExclusive(&PerfCounterListLock);
|
|
|
|
return entry;
|
|
} |