Files
mirror-processhacker/2.x/trunk/plugins/ExtendedTools/gpumon.c
T
wj32 36a4284b8d converted all annotations to SAL 2.0
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@5548 21ef857c-d57f-4fe0-8362-d861dc6d29cd
2013-11-10 06:25:03 +00:00

836 lines
29 KiB
C

/*
* Process Hacker Extended Tools -
* GPU monitoring
*
* Copyright (C) 2011 wj32
*
* 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 "exttools.h"
#include "setupapi.h"
#include "d3dkmt.h"
#include "gpumon.h"
static GUID GUID_DISPLAY_DEVICE_ARRIVAL_I = { 0x1ca05180, 0xa699, 0x450a, { 0x9a, 0x0c, 0xde, 0x4f, 0xbe, 0x3d, 0xdd, 0x89 } };
static PFND3DKMT_OPENADAPTERFROMDEVICENAME D3DKMTOpenAdapterFromDeviceName_I;
static PFND3DKMT_CLOSEADAPTER D3DKMTCloseAdapter_I;
static PFND3DKMT_QUERYSTATISTICS D3DKMTQueryStatistics_I;
static _SetupDiGetClassDevsW SetupDiGetClassDevsW_I;
static _SetupDiDestroyDeviceInfoList SetupDiDestroyDeviceInfoList_I;
static _SetupDiEnumDeviceInterfaces SetupDiEnumDeviceInterfaces_I;
static _SetupDiGetDeviceInterfaceDetailW SetupDiGetDeviceInterfaceDetailW_I;
static _SetupDiGetDeviceRegistryPropertyW SetupDiGetDeviceRegistryPropertyW_I;
BOOLEAN EtGpuEnabled;
static PPH_LIST EtpGpuAdapterList;
static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration;
ULONG EtGpuTotalNodeCount;
ULONG EtGpuTotalSegmentCount;
ULONG64 EtGpuDedicatedLimit;
ULONG64 EtGpuSharedLimit;
ULONG EtGpuNextNodeIndex = 0;
RTL_BITMAP EtGpuNodeBitMap;
PULONG EtGpuNodeBitMapBuffer;
ULONG EtGpuNodeBitMapBitsSet;
PULONG EtGpuNewNodeBitMapBuffer;
PH_UINT64_DELTA EtClockTotalRunningTimeDelta;
LARGE_INTEGER EtClockTotalRunningTimeFrequency;
PH_UINT64_DELTA EtGpuTotalRunningTimeDelta;
PH_UINT64_DELTA EtGpuSystemRunningTimeDelta;
FLOAT EtGpuNodeUsage;
PH_CIRCULAR_BUFFER_FLOAT EtGpuNodeHistory;
PH_CIRCULAR_BUFFER_ULONG EtMaxGpuNodeHistory; // ID of max. GPU usage process
PH_CIRCULAR_BUFFER_FLOAT EtMaxGpuNodeUsageHistory;
PPH_UINT64_DELTA EtGpuNodesTotalRunningTimeDelta;
PPH_CIRCULAR_BUFFER_FLOAT EtGpuNodesHistory;
ULONG64 EtGpuDedicatedUsage;
ULONG64 EtGpuSharedUsage;
PH_CIRCULAR_BUFFER_ULONG EtGpuDedicatedHistory;
PH_CIRCULAR_BUFFER_ULONG EtGpuSharedHistory;
VOID EtGpuMonitorInitialization(
VOID
)
{
if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR) && WindowsVersion >= WINDOWS_7)
{
HMODULE gdi32Handle;
HMODULE setupapiHandle;
if (gdi32Handle = GetModuleHandle(L"gdi32.dll"))
{
D3DKMTOpenAdapterFromDeviceName_I = (PVOID)GetProcAddress(gdi32Handle, "D3DKMTOpenAdapterFromDeviceName");
D3DKMTCloseAdapter_I = (PVOID)GetProcAddress(gdi32Handle, "D3DKMTCloseAdapter");
D3DKMTQueryStatistics_I = (PVOID)GetProcAddress(gdi32Handle, "D3DKMTQueryStatistics");
}
if (setupapiHandle = LoadLibrary(L"setupapi.dll"))
{
SetupDiGetClassDevsW_I = (PVOID)GetProcAddress(setupapiHandle, "SetupDiGetClassDevsW");
SetupDiDestroyDeviceInfoList_I = (PVOID)GetProcAddress(setupapiHandle, "SetupDiDestroyDeviceInfoList");
SetupDiEnumDeviceInterfaces_I = (PVOID)GetProcAddress(setupapiHandle, "SetupDiEnumDeviceInterfaces");
SetupDiGetDeviceInterfaceDetailW_I = (PVOID)GetProcAddress(setupapiHandle, "SetupDiGetDeviceInterfaceDetailW");
SetupDiGetDeviceRegistryPropertyW_I = (PVOID)GetProcAddress(setupapiHandle, "SetupDiGetDeviceRegistryPropertyW");
}
if (
D3DKMTOpenAdapterFromDeviceName_I &&
D3DKMTCloseAdapter_I &&
D3DKMTQueryStatistics_I &&
SetupDiGetClassDevsW_I &&
SetupDiDestroyDeviceInfoList_I &&
SetupDiEnumDeviceInterfaces_I &&
SetupDiGetDeviceInterfaceDetailW_I
)
{
EtpGpuAdapterList = PhCreateList(4);
if (EtpInitializeD3DStatistics() && EtpGpuAdapterList->Count != 0)
EtGpuEnabled = TRUE;
}
}
if (EtGpuEnabled)
{
ULONG sampleCount;
ULONG i;
PPH_STRING bitmapString;
sampleCount = PhGetIntegerSetting(L"SampleCount");
PhInitializeCircularBuffer_FLOAT(&EtGpuNodeHistory, sampleCount);
PhInitializeCircularBuffer_ULONG(&EtMaxGpuNodeHistory, sampleCount);
PhInitializeCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, sampleCount);
PhInitializeCircularBuffer_ULONG(&EtGpuDedicatedHistory, sampleCount);
PhInitializeCircularBuffer_ULONG(&EtGpuSharedHistory, sampleCount);
EtGpuNodesTotalRunningTimeDelta = PhAllocate(sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount);
memset(EtGpuNodesTotalRunningTimeDelta, 0, sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount);
EtGpuNodesHistory = PhAllocate(sizeof(PH_CIRCULAR_BUFFER_FLOAT) * EtGpuTotalNodeCount);
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
PhInitializeCircularBuffer_FLOAT(&EtGpuNodesHistory[i], sampleCount);
}
PhRegisterCallback(
&PhProcessesUpdatedEvent,
ProcessesUpdatedCallback,
NULL,
&ProcessesUpdatedCallbackRegistration
);
// Load the node bitmap.
bitmapString = PhGetStringSetting(SETTING_NAME_GPU_NODE_BITMAP);
if (!(bitmapString->Length & 3) && bitmapString->Length / 4 <= BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount))
{
PhHexStringToBuffer(&bitmapString->sr, (PUCHAR)EtGpuNodeBitMapBuffer);
EtGpuNodeBitMapBitsSet = RtlNumberOfSetBits(&EtGpuNodeBitMap);
}
PhDereferenceObject(bitmapString);
// Fix up the node bitmap.
// If "Microsoft Basic Render Driver" is the only adapter selected, try to select other adapters.
if (EtGpuNodeBitMapBitsSet == 1 && EtpGpuAdapterList->Count > 1)
{
BOOLEAN basicDriverSelected = FALSE;
for (i = 0; i < EtpGpuAdapterList->Count; i++)
{
PETP_GPU_ADAPTER gpuAdapter = EtpGpuAdapterList->Items[i];
if (PhEqualString2(gpuAdapter->Description, L"Microsoft Basic Render Driver", TRUE))
{
if (RtlCheckBit(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex))
basicDriverSelected = TRUE;
break;
}
}
if (basicDriverSelected)
{
RtlClearAllBits(&EtGpuNodeBitMap);
EtGpuNodeBitMapBitsSet = 0;
// Select the first node of every other adapter.
for (i = 0; i < EtpGpuAdapterList->Count; i++)
{
PETP_GPU_ADAPTER gpuAdapter = EtpGpuAdapterList->Items[i];
if (!PhEqualString2(gpuAdapter->Description, L"Microsoft Basic Render Driver", TRUE))
{
RtlSetBits(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex, 1);
EtGpuNodeBitMapBitsSet++;
}
}
}
}
}
}
BOOLEAN EtpInitializeD3DStatistics(
VOID
)
{
LOGICAL result;
HDEVINFO deviceInfoSet;
ULONG memberIndex;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData;
SP_DEVINFO_DATA deviceInfoData;
ULONG detailDataSize;
D3DKMT_OPENADAPTERFROMDEVICENAME openAdapterFromDeviceName;
D3DKMT_QUERYSTATISTICS queryStatistics;
deviceInfoSet = SetupDiGetClassDevsW_I(&GUID_DISPLAY_DEVICE_ARRIVAL_I, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (!deviceInfoSet)
return FALSE;
memberIndex = 0;
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
while (SetupDiEnumDeviceInterfaces_I(deviceInfoSet, NULL, &GUID_DISPLAY_DEVICE_ARRIVAL_I, memberIndex, &deviceInterfaceData))
{
detailDataSize = 0x100;
detailData = PhAllocate(detailDataSize);
detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (!(result = SetupDiGetDeviceInterfaceDetailW_I(deviceInfoSet, &deviceInterfaceData, detailData, detailDataSize, &detailDataSize, &deviceInfoData)) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
PhFree(detailData);
detailData = PhAllocate(detailDataSize);
if (detailDataSize >= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA))
detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
result = SetupDiGetDeviceInterfaceDetailW_I(deviceInfoSet, &deviceInterfaceData, detailData, detailDataSize, &detailDataSize, &deviceInfoData);
}
if (result)
{
openAdapterFromDeviceName.pDeviceName = detailData->DevicePath;
if (NT_SUCCESS(D3DKMTOpenAdapterFromDeviceName_I(&openAdapterFromDeviceName)))
{
memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_ADAPTER;
queryStatistics.AdapterLuid = openAdapterFromDeviceName.AdapterLuid;
if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
{
PETP_GPU_ADAPTER gpuAdapter;
ULONG i;
gpuAdapter = EtpAllocateGpuAdapter(queryStatistics.QueryResult.AdapterInformation.NbSegments);
gpuAdapter->AdapterLuid = openAdapterFromDeviceName.AdapterLuid;
gpuAdapter->Description = EtpQueryDeviceDescription(deviceInfoSet, &deviceInfoData);
gpuAdapter->NodeCount = queryStatistics.QueryResult.AdapterInformation.NodeCount;
gpuAdapter->SegmentCount = queryStatistics.QueryResult.AdapterInformation.NbSegments;
RtlInitializeBitMap(&gpuAdapter->ApertureBitMap, gpuAdapter->ApertureBitMapBuffer, queryStatistics.QueryResult.AdapterInformation.NbSegments);
PhAddItemList(EtpGpuAdapterList, gpuAdapter);
EtGpuTotalNodeCount += gpuAdapter->NodeCount;
EtGpuTotalSegmentCount += gpuAdapter->SegmentCount;
gpuAdapter->FirstNodeIndex = EtGpuNextNodeIndex;
EtGpuNextNodeIndex += gpuAdapter->NodeCount;
for (i = 0; i < gpuAdapter->SegmentCount; i++)
{
memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_SEGMENT;
queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
queryStatistics.QuerySegment.SegmentId = i;
if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
{
ULONG64 commitLimit;
ULONG aperture;
if (WindowsVersion >= WINDOWS_8)
{
commitLimit = queryStatistics.QueryResult.SegmentInformation.CommitLimit;
aperture = queryStatistics.QueryResult.SegmentInformation.Aperture;
}
else
{
commitLimit = queryStatistics.QueryResult.SegmentInformationV1.CommitLimit;
aperture = queryStatistics.QueryResult.SegmentInformationV1.Aperture;
}
if (aperture)
EtGpuSharedLimit += commitLimit;
else
EtGpuDedicatedLimit += commitLimit;
if (aperture)
RtlSetBits(&gpuAdapter->ApertureBitMap, i, 1);
}
}
}
}
}
PhFree(detailData);
memberIndex++;
}
SetupDiDestroyDeviceInfoList_I(deviceInfoSet);
EtGpuNodeBitMapBuffer = PhAllocate(BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount));
RtlInitializeBitMap(&EtGpuNodeBitMap, EtGpuNodeBitMapBuffer, EtGpuTotalNodeCount);
RtlSetBits(&EtGpuNodeBitMap, 0, 1);
EtGpuNodeBitMapBitsSet = 1;
return TRUE;
}
PETP_GPU_ADAPTER EtpAllocateGpuAdapter(
_In_ ULONG NumberOfSegments
)
{
PETP_GPU_ADAPTER adapter;
SIZE_T sizeNeeded;
sizeNeeded = FIELD_OFFSET(ETP_GPU_ADAPTER, ApertureBitMapBuffer);
sizeNeeded += BYTES_NEEDED_FOR_BITS(NumberOfSegments);
adapter = PhAllocate(sizeNeeded);
memset(adapter, 0, sizeNeeded);
return adapter;
}
PPH_STRING EtpQueryDeviceDescription(
_In_ HDEVINFO DeviceInfoSet,
_In_ PSP_DEVINFO_DATA DeviceInfoData
)
{
LOGICAL result;
PPH_STRING string;
ULONG bufferSize;
if (!SetupDiGetDeviceRegistryPropertyW_I)
return NULL;
bufferSize = 0x40;
string = PhCreateStringEx(NULL, bufferSize);
if (!(result = SetupDiGetDeviceRegistryPropertyW_I(
DeviceInfoSet,
DeviceInfoData,
SPDRP_DEVICEDESC,
NULL,
(PBYTE)string->Buffer,
bufferSize,
&bufferSize
)) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
PhDereferenceObject(string);
string = PhCreateStringEx(NULL, bufferSize);
result = SetupDiGetDeviceRegistryPropertyW_I(
DeviceInfoSet,
DeviceInfoData,
SPDRP_DEVICEDESC,
NULL,
(PBYTE)string->Buffer,
bufferSize,
NULL
);
}
if (!result)
{
PhDereferenceObject(string);
return NULL;
}
PhTrimToNullTerminatorString(string);
return string;
}
static VOID EtpUpdateSegmentInformation(
_In_opt_ PET_PROCESS_BLOCK Block
)
{
ULONG i;
ULONG j;
PETP_GPU_ADAPTER gpuAdapter;
D3DKMT_QUERYSTATISTICS queryStatistics;
ULONG64 dedicatedUsage;
ULONG64 sharedUsage;
if (Block && !Block->ProcessItem->QueryHandle)
return;
dedicatedUsage = 0;
sharedUsage = 0;
for (i = 0; i < EtpGpuAdapterList->Count; i++)
{
gpuAdapter = EtpGpuAdapterList->Items[i];
for (j = 0; j < gpuAdapter->SegmentCount; j++)
{
memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
if (Block)
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT;
else
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_SEGMENT;
queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
if (Block)
{
queryStatistics.hProcess = Block->ProcessItem->QueryHandle;
queryStatistics.QueryProcessSegment.SegmentId = j;
}
else
{
queryStatistics.QuerySegment.SegmentId = j;
}
if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
{
if (Block)
{
ULONG64 bytesCommitted;
if (WindowsVersion >= WINDOWS_8)
{
bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted;
}
else
{
bytesCommitted = (ULONG)queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted;
}
if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j))
sharedUsage += bytesCommitted;
else
dedicatedUsage += bytesCommitted;
}
else
{
ULONG64 bytesCommitted;
if (WindowsVersion >= WINDOWS_8)
{
bytesCommitted = queryStatistics.QueryResult.SegmentInformation.BytesCommitted;
}
else
{
bytesCommitted = queryStatistics.QueryResult.SegmentInformationV1.BytesCommitted;
}
if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j))
sharedUsage += bytesCommitted;
else
dedicatedUsage += bytesCommitted;
}
}
}
}
if (Block)
{
Block->GpuDedicatedUsage = dedicatedUsage;
Block->GpuSharedUsage = sharedUsage;
}
else
{
EtGpuDedicatedUsage = dedicatedUsage;
EtGpuSharedUsage = sharedUsage;
}
}
static VOID EtpUpdateNodeInformation(
_In_opt_ PET_PROCESS_BLOCK Block
)
{
ULONG i;
ULONG j;
PETP_GPU_ADAPTER gpuAdapter;
D3DKMT_QUERYSTATISTICS queryStatistics;
ULONG64 totalRunningTime;
ULONG64 systemRunningTime;
if (Block && !Block->ProcessItem->QueryHandle)
return;
totalRunningTime = 0;
systemRunningTime = 0;
for (i = 0; i < EtpGpuAdapterList->Count; i++)
{
gpuAdapter = EtpGpuAdapterList->Items[i];
for (j = 0; j < gpuAdapter->NodeCount; j++)
{
if (Block && !RtlCheckBit(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j))
continue;
memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
if (Block)
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_NODE;
else
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_NODE;
queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
if (Block)
{
queryStatistics.hProcess = Block->ProcessItem->QueryHandle;
queryStatistics.QueryProcessNode.NodeId = j;
}
else
{
queryStatistics.QueryNode.NodeId = j;
}
if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
{
if (Block)
{
totalRunningTime += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime.QuadPart;
}
else
{
ULONG nodeIndex;
nodeIndex = gpuAdapter->FirstNodeIndex + j;
PhUpdateDelta(&EtGpuNodesTotalRunningTimeDelta[nodeIndex], queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart);
if (RtlCheckBit(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j))
{
totalRunningTime += queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart;
systemRunningTime += queryStatistics.QueryResult.NodeInformation.SystemInformation.RunningTime.QuadPart;
}
}
}
}
}
if (Block)
{
PhUpdateDelta(&Block->GpuRunningTimeDelta, totalRunningTime);
}
else
{
LARGE_INTEGER performanceCounter;
NtQueryPerformanceCounter(&performanceCounter, &EtClockTotalRunningTimeFrequency);
PhUpdateDelta(&EtClockTotalRunningTimeDelta, performanceCounter.QuadPart);
PhUpdateDelta(&EtGpuTotalRunningTimeDelta, totalRunningTime);
PhUpdateDelta(&EtGpuSystemRunningTimeDelta, systemRunningTime);
}
}
static VOID NTAPI ProcessesUpdatedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
static ULONG runCount = 0; // MUST keep in sync with runCount in process provider
DOUBLE elapsedTime; // total GPU node elapsed time in micro-seconds
ULONG i;
PLIST_ENTRY listEntry;
FLOAT maxNodeValue = 0;
PET_PROCESS_BLOCK maxNodeBlock = NULL;
// Update global statistics.
EtpUpdateSegmentInformation(NULL);
EtpUpdateNodeInformation(NULL);
elapsedTime = (DOUBLE)EtClockTotalRunningTimeDelta.Delta * 10000000 / EtClockTotalRunningTimeFrequency.QuadPart;
if (elapsedTime != 0)
EtGpuNodeUsage = (FLOAT)(EtGpuTotalRunningTimeDelta.Delta / (elapsedTime * EtGpuNodeBitMapBitsSet));
else
EtGpuNodeUsage = 0;
if (EtGpuNodeUsage > 1)
EtGpuNodeUsage = 1;
// Do the update of the node bitmap if needed.
if (EtGpuNewNodeBitMapBuffer)
{
PULONG newBuffer;
newBuffer = _InterlockedExchangePointer(&EtGpuNewNodeBitMapBuffer, NULL);
if (newBuffer)
{
PhFree(EtGpuNodeBitMap.Buffer);
EtGpuNodeBitMap.Buffer = newBuffer;
EtGpuNodeBitMapBuffer = newBuffer;
EtGpuNodeBitMapBitsSet = RtlNumberOfSetBits(&EtGpuNodeBitMap);
EtSaveGpuMonitorSettings();
}
}
// Update per-process statistics.
// Note: no lock is needed because we only ever modify the list on this same thread.
listEntry = EtProcessBlockListHead.Flink;
while (listEntry != &EtProcessBlockListHead)
{
PET_PROCESS_BLOCK block;
block = CONTAINING_RECORD(listEntry, ET_PROCESS_BLOCK, ListEntry);
EtpUpdateSegmentInformation(block);
EtpUpdateNodeInformation(block);
if (elapsedTime != 0)
{
block->GpuNodeUsage = (FLOAT)(block->GpuRunningTimeDelta.Delta / (elapsedTime * EtGpuNodeBitMapBitsSet));
if (block->GpuNodeUsage > 1)
block->GpuNodeUsage = 1;
}
if (maxNodeValue < block->GpuNodeUsage)
{
maxNodeValue = block->GpuNodeUsage;
maxNodeBlock = block;
}
listEntry = listEntry->Flink;
}
// Update history buffers.
if (runCount != 0)
{
PhAddItemCircularBuffer_FLOAT(&EtGpuNodeHistory, EtGpuNodeUsage);
PhAddItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, (ULONG)(EtGpuDedicatedUsage / PAGE_SIZE));
PhAddItemCircularBuffer_ULONG(&EtGpuSharedHistory, (ULONG)(EtGpuSharedUsage / PAGE_SIZE));
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
FLOAT usage;
usage = (FLOAT)(EtGpuNodesTotalRunningTimeDelta[i].Delta / elapsedTime);
if (usage > 1)
usage = 1;
PhAddItemCircularBuffer_FLOAT(&EtGpuNodesHistory[i], usage);
}
if (maxNodeBlock)
{
PhAddItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, (ULONG)maxNodeBlock->ProcessItem->ProcessId);
PhAddItemCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, maxNodeBlock->GpuNodeUsage);
PhReferenceProcessRecordForStatistics(maxNodeBlock->ProcessItem->Record);
}
else
{
PhAddItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, (ULONG)NULL);
PhAddItemCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, 0);
}
}
runCount++;
}
VOID EtSaveGpuMonitorSettings(
VOID
)
{
PPH_STRING string;
string = PhBufferToHexString((PUCHAR)EtGpuNodeBitMapBuffer, BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount));
PhSetStringSetting2(SETTING_NAME_GPU_NODE_BITMAP, &string->sr);
PhDereferenceObject(string);
}
ULONG EtGetGpuAdapterCount(
VOID
)
{
return EtpGpuAdapterList->Count;
}
ULONG EtGetGpuAdapterIndexFromNodeIndex(
_In_ ULONG NodeIndex
)
{
ULONG i;
PETP_GPU_ADAPTER gpuAdapter;
for (i = 0; i < EtpGpuAdapterList->Count; i++)
{
gpuAdapter = EtpGpuAdapterList->Items[i];
if (NodeIndex >= gpuAdapter->FirstNodeIndex && NodeIndex < gpuAdapter->FirstNodeIndex + gpuAdapter->NodeCount)
return i;
}
return -1;
}
PPH_STRING EtGetGpuAdapterDescription(
_In_ ULONG Index
)
{
PPH_STRING description;
if (Index >= EtpGpuAdapterList->Count)
return NULL;
description = ((PETP_GPU_ADAPTER)EtpGpuAdapterList->Items[Index])->Description;
if (description)
{
PhReferenceObject(description);
return description;
}
else
{
return NULL;
}
}
VOID EtAllocateGpuNodeBitMap(
_Out_ PRTL_BITMAP BitMap
)
{
SIZE_T numberOfBytes;
numberOfBytes = BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount);
BitMap->Buffer = PhAllocate(numberOfBytes);
BitMap->SizeOfBitMap = EtGpuTotalNodeCount;
memset(BitMap->Buffer, 0, numberOfBytes);
}
VOID EtUpdateGpuNodeBitMap(
_In_ PRTL_BITMAP NewBitMap
)
{
PULONG buffer;
buffer = _InterlockedExchangePointer(&EtGpuNewNodeBitMapBuffer, NewBitMap->Buffer);
if (buffer)
PhFree(buffer);
}
VOID EtQueryProcessGpuStatistics(
_In_ HANDLE ProcessHandle,
_Out_ PET_PROCESS_GPU_STATISTICS Statistics
)
{
NTSTATUS status;
ULONG i;
ULONG j;
PETP_GPU_ADAPTER gpuAdapter;
D3DKMT_QUERYSTATISTICS queryStatistics;
memset(Statistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS));
for (i = 0; i < EtpGpuAdapterList->Count; i++)
{
gpuAdapter = EtpGpuAdapterList->Items[i];
Statistics->SegmentCount += gpuAdapter->SegmentCount;
Statistics->NodeCount += gpuAdapter->NodeCount;
for (j = 0; j < gpuAdapter->SegmentCount; j++)
{
memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT;
queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
queryStatistics.hProcess = ProcessHandle;
queryStatistics.QueryProcessSegment.SegmentId = j;
if (NT_SUCCESS(status = D3DKMTQueryStatistics_I(&queryStatistics)))
{
ULONG64 bytesCommitted;
if (WindowsVersion >= WINDOWS_8)
{
bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted;
}
else
{
bytesCommitted = (ULONG)queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted;
}
if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j))
Statistics->SharedCommitted += bytesCommitted;
else
Statistics->DedicatedCommitted += bytesCommitted;
}
}
for (j = 0; j < gpuAdapter->NodeCount; j++)
{
memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_NODE;
queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
queryStatistics.hProcess = ProcessHandle;
queryStatistics.QueryProcessNode.NodeId = j;
if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
{
Statistics->RunningTime += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime.QuadPart;
Statistics->ContextSwitches += queryStatistics.QueryResult.ProcessNodeInformation.ContextSwitch;
}
}
memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS;
queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
queryStatistics.hProcess = ProcessHandle;
if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
{
Statistics->BytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.BytesAllocated;
Statistics->BytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.BytesReserved;
Statistics->WriteCombinedBytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.WriteCombinedBytesAllocated;
Statistics->WriteCombinedBytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.WriteCombinedBytesReserved;
Statistics->CachedBytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.CachedBytesAllocated;
Statistics->CachedBytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.CachedBytesReserved;
Statistics->SectionBytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.SectionBytesAllocated;
Statistics->SectionBytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.SectionBytesReserved;
}
}
}