Process Hacker
gpumon.c
Go to the documentation of this file.
1 /*
2  * Process Hacker Extended Tools -
3  * GPU monitoring
4  *
5  * Copyright (C) 2011-2015 wj32
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "exttools.h"
24 #include "setupapi.h"
25 #include "d3dkmt.h"
26 #include "gpumon.h"
27 
28 static GUID GUID_DISPLAY_DEVICE_ARRIVAL_I = { 0x1ca05180, 0xa699, 0x450a, { 0x9a, 0x0c, 0xde, 0x4f, 0xbe, 0x3d, 0xdd, 0x89 } };
29 
30 static PFND3DKMT_OPENADAPTERFROMDEVICENAME D3DKMTOpenAdapterFromDeviceName_I;
31 static PFND3DKMT_CLOSEADAPTER D3DKMTCloseAdapter_I;
32 static PFND3DKMT_QUERYSTATISTICS D3DKMTQueryStatistics_I;
33 static _SetupDiGetClassDevsW SetupDiGetClassDevsW_I;
34 static _SetupDiDestroyDeviceInfoList SetupDiDestroyDeviceInfoList_I;
35 static _SetupDiEnumDeviceInterfaces SetupDiEnumDeviceInterfaces_I;
36 static _SetupDiGetDeviceInterfaceDetailW SetupDiGetDeviceInterfaceDetailW_I;
37 static _SetupDiGetDeviceRegistryPropertyW SetupDiGetDeviceRegistryPropertyW_I;
38 
39 BOOLEAN EtGpuEnabled;
40 static PPH_LIST EtpGpuAdapterList;
41 static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration;
42 
52 
58 PH_CIRCULAR_BUFFER_FLOAT EtGpuNodeHistory;
59 PH_CIRCULAR_BUFFER_ULONG EtMaxGpuNodeHistory; // ID of max. GPU usage process
60 PH_CIRCULAR_BUFFER_FLOAT EtMaxGpuNodeUsageHistory;
61 
63 PPH_CIRCULAR_BUFFER_FLOAT EtGpuNodesHistory;
64 
67 PH_CIRCULAR_BUFFER_ULONG EtGpuDedicatedHistory;
68 PH_CIRCULAR_BUFFER_ULONG EtGpuSharedHistory;
69 
71  VOID
72  )
73 {
75  {
76  HMODULE gdi32Handle;
77  HMODULE setupapiHandle;
78 
79  if (gdi32Handle = GetModuleHandle(L"gdi32.dll"))
80  {
81  D3DKMTOpenAdapterFromDeviceName_I = (PVOID)GetProcAddress(gdi32Handle, "D3DKMTOpenAdapterFromDeviceName");
82  D3DKMTCloseAdapter_I = (PVOID)GetProcAddress(gdi32Handle, "D3DKMTCloseAdapter");
83  D3DKMTQueryStatistics_I = (PVOID)GetProcAddress(gdi32Handle, "D3DKMTQueryStatistics");
84  }
85 
86  if (setupapiHandle = LoadLibrary(L"setupapi.dll"))
87  {
88  SetupDiGetClassDevsW_I = (PVOID)GetProcAddress(setupapiHandle, "SetupDiGetClassDevsW");
89  SetupDiDestroyDeviceInfoList_I = (PVOID)GetProcAddress(setupapiHandle, "SetupDiDestroyDeviceInfoList");
90  SetupDiEnumDeviceInterfaces_I = (PVOID)GetProcAddress(setupapiHandle, "SetupDiEnumDeviceInterfaces");
91  SetupDiGetDeviceInterfaceDetailW_I = (PVOID)GetProcAddress(setupapiHandle, "SetupDiGetDeviceInterfaceDetailW");
92  SetupDiGetDeviceRegistryPropertyW_I = (PVOID)GetProcAddress(setupapiHandle, "SetupDiGetDeviceRegistryPropertyW");
93  }
94 
95  if (
96  D3DKMTOpenAdapterFromDeviceName_I &&
97  D3DKMTCloseAdapter_I &&
98  D3DKMTQueryStatistics_I &&
99  SetupDiGetClassDevsW_I &&
100  SetupDiDestroyDeviceInfoList_I &&
101  SetupDiEnumDeviceInterfaces_I &&
102  SetupDiGetDeviceInterfaceDetailW_I
103  )
104  {
105  EtpGpuAdapterList = PhCreateList(4);
106 
107  if (EtpInitializeD3DStatistics() && EtpGpuAdapterList->Count != 0)
108  EtGpuEnabled = TRUE;
109  }
110  }
111 
112  if (EtGpuEnabled)
113  {
114  ULONG sampleCount;
115  ULONG i;
116  ULONG j;
117  PPH_STRING bitmapString;
118  D3DKMT_QUERYSTATISTICS queryStatistics;
119 
120  sampleCount = PhGetIntegerSetting(L"SampleCount");
121  PhInitializeCircularBuffer_FLOAT(&EtGpuNodeHistory, sampleCount);
122  PhInitializeCircularBuffer_ULONG(&EtMaxGpuNodeHistory, sampleCount);
123  PhInitializeCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, sampleCount);
124  PhInitializeCircularBuffer_ULONG(&EtGpuDedicatedHistory, sampleCount);
125  PhInitializeCircularBuffer_ULONG(&EtGpuSharedHistory, sampleCount);
126 
127  EtGpuNodesTotalRunningTimeDelta = PhAllocate(sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount);
128  memset(EtGpuNodesTotalRunningTimeDelta, 0, sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount);
129  EtGpuNodesHistory = PhAllocate(sizeof(PH_CIRCULAR_BUFFER_FLOAT) * EtGpuTotalNodeCount);
130 
131  for (i = 0; i < EtGpuTotalNodeCount; i++)
132  {
133  PhInitializeCircularBuffer_FLOAT(&EtGpuNodesHistory[i], sampleCount);
134  }
135 
139  NULL,
140  &ProcessesUpdatedCallbackRegistration
141  );
142 
143  // Load the node bitmap.
144 
146 
147  if (!(bitmapString->Length & 3) && bitmapString->Length / 4 <= BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount))
148  {
149  PhHexStringToBuffer(&bitmapString->sr, (PUCHAR)EtGpuNodeBitMapBuffer);
150  EtGpuNodeBitMapBitsSet = RtlNumberOfSetBits(&EtGpuNodeBitMap);
151  }
152 
153  PhDereferenceObject(bitmapString);
154 
155  // Fix up the node bitmap if the current node count differs from what we've seen.
156  if (EtGpuTotalNodeCount != PhGetIntegerSetting(SETTING_NAME_GPU_LAST_NODE_COUNT))
157  {
158  RtlClearAllBits(&EtGpuNodeBitMap);
160 
161  for (i = 0; i < EtpGpuAdapterList->Count; i++)
162  {
163  PETP_GPU_ADAPTER gpuAdapter = EtpGpuAdapterList->Items[i];
164 
165  for (j = 0; j < gpuAdapter->NodeCount; j++)
166  {
167  memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
168  queryStatistics.Type = D3DKMT_QUERYSTATISTICS_NODE;
169  queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
170  queryStatistics.QueryNode.NodeId = j;
171 
172  if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
173  {
174  // The numbers below are quite arbitrary.
175  if (queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart != 0 &&
177  {
178  RtlSetBits(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j, 1);
180  }
181  }
182  }
183  }
184 
185  // Just in case
186  if (EtGpuNodeBitMapBitsSet == 0)
187  {
188  RtlSetBits(&EtGpuNodeBitMap, 0, 1);
190  }
191 
193  }
194  }
195 }
196 
198  VOID
199  )
200 {
201  LOGICAL result;
202  HDEVINFO deviceInfoSet;
203  ULONG memberIndex;
204  SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
205  PSP_DEVICE_INTERFACE_DETAIL_DATA detailData;
206  SP_DEVINFO_DATA deviceInfoData;
207  ULONG detailDataSize;
208  D3DKMT_OPENADAPTERFROMDEVICENAME openAdapterFromDeviceName;
209  D3DKMT_QUERYSTATISTICS queryStatistics;
210 
211  deviceInfoSet = SetupDiGetClassDevsW_I(&GUID_DISPLAY_DEVICE_ARRIVAL_I, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
212 
213  if (!deviceInfoSet)
214  return FALSE;
215 
216  memberIndex = 0;
217  deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
218 
219  while (SetupDiEnumDeviceInterfaces_I(deviceInfoSet, NULL, &GUID_DISPLAY_DEVICE_ARRIVAL_I, memberIndex, &deviceInterfaceData))
220  {
221  detailDataSize = 0x100;
222  detailData = PhAllocate(detailDataSize);
223  detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
224  deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
225 
226  if (!(result = SetupDiGetDeviceInterfaceDetailW_I(deviceInfoSet, &deviceInterfaceData, detailData, detailDataSize, &detailDataSize, &deviceInfoData)) &&
227  GetLastError() == ERROR_INSUFFICIENT_BUFFER)
228  {
229  PhFree(detailData);
230  detailData = PhAllocate(detailDataSize);
231 
232  if (detailDataSize >= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA))
233  detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
234 
235  result = SetupDiGetDeviceInterfaceDetailW_I(deviceInfoSet, &deviceInterfaceData, detailData, detailDataSize, &detailDataSize, &deviceInfoData);
236  }
237 
238  if (result)
239  {
240  openAdapterFromDeviceName.pDeviceName = detailData->DevicePath;
241 
242  if (NT_SUCCESS(D3DKMTOpenAdapterFromDeviceName_I(&openAdapterFromDeviceName)))
243  {
244  memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
245  queryStatistics.Type = D3DKMT_QUERYSTATISTICS_ADAPTER;
246  queryStatistics.AdapterLuid = openAdapterFromDeviceName.AdapterLuid;
247 
248  if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
249  {
250  PETP_GPU_ADAPTER gpuAdapter;
251  ULONG i;
252 
253  gpuAdapter = EtpAllocateGpuAdapter(queryStatistics.QueryResult.AdapterInformation.NbSegments);
254  gpuAdapter->AdapterLuid = openAdapterFromDeviceName.AdapterLuid;
255  gpuAdapter->Description = EtpQueryDeviceDescription(deviceInfoSet, &deviceInfoData);
256  gpuAdapter->NodeCount = queryStatistics.QueryResult.AdapterInformation.NodeCount;
257  gpuAdapter->SegmentCount = queryStatistics.QueryResult.AdapterInformation.NbSegments;
259 
260  PhAddItemList(EtpGpuAdapterList, gpuAdapter);
261  EtGpuTotalNodeCount += gpuAdapter->NodeCount;
262  EtGpuTotalSegmentCount += gpuAdapter->SegmentCount;
263 
264  gpuAdapter->FirstNodeIndex = EtGpuNextNodeIndex;
265  EtGpuNextNodeIndex += gpuAdapter->NodeCount;
266 
267  for (i = 0; i < gpuAdapter->SegmentCount; i++)
268  {
269  memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
270  queryStatistics.Type = D3DKMT_QUERYSTATISTICS_SEGMENT;
271  queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
272  queryStatistics.QuerySegment.SegmentId = i;
273 
274  if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
275  {
276  ULONG64 commitLimit;
277  ULONG aperture;
278 
279  if (WindowsVersion >= WINDOWS_8)
280  {
281  commitLimit = queryStatistics.QueryResult.SegmentInformation.CommitLimit;
282  aperture = queryStatistics.QueryResult.SegmentInformation.Aperture;
283  }
284  else
285  {
286  commitLimit = queryStatistics.QueryResult.SegmentInformationV1.CommitLimit;
287  aperture = queryStatistics.QueryResult.SegmentInformationV1.Aperture;
288  }
289 
290  if (aperture)
291  EtGpuSharedLimit += commitLimit;
292  else
293  EtGpuDedicatedLimit += commitLimit;
294 
295  if (aperture)
296  RtlSetBits(&gpuAdapter->ApertureBitMap, i, 1);
297  }
298  }
299  }
300  }
301  }
302 
303  PhFree(detailData);
304 
305  memberIndex++;
306  }
307 
308  SetupDiDestroyDeviceInfoList_I(deviceInfoSet);
309 
312  RtlSetBits(&EtGpuNodeBitMap, 0, 1);
314 
315  return TRUE;
316 }
317 
319  _In_ ULONG NumberOfSegments
320  )
321 {
322  PETP_GPU_ADAPTER adapter;
323  SIZE_T sizeNeeded;
324 
325  sizeNeeded = FIELD_OFFSET(ETP_GPU_ADAPTER, ApertureBitMapBuffer);
326  sizeNeeded += BYTES_NEEDED_FOR_BITS(NumberOfSegments);
327 
328  adapter = PhAllocate(sizeNeeded);
329  memset(adapter, 0, sizeNeeded);
330 
331  return adapter;
332 }
333 
335  _In_ HDEVINFO DeviceInfoSet,
336  _In_ PSP_DEVINFO_DATA DeviceInfoData
337  )
338 {
339  LOGICAL result;
340  PPH_STRING string;
341  ULONG bufferSize;
342 
343  if (!SetupDiGetDeviceRegistryPropertyW_I)
344  return NULL;
345 
346  bufferSize = 0x40;
347  string = PhCreateStringEx(NULL, bufferSize);
348 
349  if (!(result = SetupDiGetDeviceRegistryPropertyW_I(
350  DeviceInfoSet,
351  DeviceInfoData,
352  SPDRP_DEVICEDESC,
353  NULL,
354  (PBYTE)string->Buffer,
355  bufferSize,
356  &bufferSize
357  )) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
358  {
359  PhDereferenceObject(string);
360  string = PhCreateStringEx(NULL, bufferSize);
361 
362  result = SetupDiGetDeviceRegistryPropertyW_I(
363  DeviceInfoSet,
364  DeviceInfoData,
365  SPDRP_DEVICEDESC,
366  NULL,
367  (PBYTE)string->Buffer,
368  bufferSize,
369  NULL
370  );
371  }
372 
373  if (!result)
374  {
375  PhDereferenceObject(string);
376  return NULL;
377  }
378 
380 
381  return string;
382 }
383 
384 static VOID EtpUpdateSegmentInformation(
385  _In_opt_ PET_PROCESS_BLOCK Block
386  )
387 {
388  ULONG i;
389  ULONG j;
390  PETP_GPU_ADAPTER gpuAdapter;
391  D3DKMT_QUERYSTATISTICS queryStatistics;
392  ULONG64 dedicatedUsage;
393  ULONG64 sharedUsage;
394 
395  if (Block && !Block->ProcessItem->QueryHandle)
396  return;
397 
398  dedicatedUsage = 0;
399  sharedUsage = 0;
400 
401  for (i = 0; i < EtpGpuAdapterList->Count; i++)
402  {
403  gpuAdapter = EtpGpuAdapterList->Items[i];
404 
405  for (j = 0; j < gpuAdapter->SegmentCount; j++)
406  {
407  memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
408 
409  if (Block)
411  else
412  queryStatistics.Type = D3DKMT_QUERYSTATISTICS_SEGMENT;
413 
414  queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
415 
416  if (Block)
417  {
418  queryStatistics.hProcess = Block->ProcessItem->QueryHandle;
419  queryStatistics.QueryProcessSegment.SegmentId = j;
420  }
421  else
422  {
423  queryStatistics.QuerySegment.SegmentId = j;
424  }
425 
426  if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
427  {
428  if (Block)
429  {
430  ULONG64 bytesCommitted;
431 
432  if (WindowsVersion >= WINDOWS_8)
433  {
434  bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted;
435  }
436  else
437  {
438  bytesCommitted = (ULONG)queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted;
439  }
440 
441  if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j))
442  sharedUsage += bytesCommitted;
443  else
444  dedicatedUsage += bytesCommitted;
445  }
446  else
447  {
448  ULONG64 bytesCommitted;
449 
450  if (WindowsVersion >= WINDOWS_8)
451  {
452  bytesCommitted = queryStatistics.QueryResult.SegmentInformation.BytesCommitted;
453  }
454  else
455  {
456  bytesCommitted = queryStatistics.QueryResult.SegmentInformationV1.BytesCommitted;
457  }
458 
459  if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j))
460  sharedUsage += bytesCommitted;
461  else
462  dedicatedUsage += bytesCommitted;
463  }
464  }
465  }
466  }
467 
468  if (Block)
469  {
470  Block->GpuDedicatedUsage = dedicatedUsage;
471  Block->GpuSharedUsage = sharedUsage;
472  }
473  else
474  {
475  EtGpuDedicatedUsage = dedicatedUsage;
476  EtGpuSharedUsage = sharedUsage;
477  }
478 }
479 
480 static VOID EtpUpdateNodeInformation(
481  _In_opt_ PET_PROCESS_BLOCK Block
482  )
483 {
484  ULONG i;
485  ULONG j;
486  PETP_GPU_ADAPTER gpuAdapter;
487  D3DKMT_QUERYSTATISTICS queryStatistics;
488  ULONG64 totalRunningTime;
489  ULONG64 systemRunningTime;
490 
491  if (Block && !Block->ProcessItem->QueryHandle)
492  return;
493 
494  totalRunningTime = 0;
495  systemRunningTime = 0;
496 
497  for (i = 0; i < EtpGpuAdapterList->Count; i++)
498  {
499  gpuAdapter = EtpGpuAdapterList->Items[i];
500 
501  for (j = 0; j < gpuAdapter->NodeCount; j++)
502  {
503  if (Block && !RtlCheckBit(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j))
504  continue;
505 
506  memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
507 
508  if (Block)
509  queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_NODE;
510  else
511  queryStatistics.Type = D3DKMT_QUERYSTATISTICS_NODE;
512 
513  queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
514 
515  if (Block)
516  {
517  queryStatistics.hProcess = Block->ProcessItem->QueryHandle;
518  queryStatistics.QueryProcessNode.NodeId = j;
519  }
520  else
521  {
522  queryStatistics.QueryNode.NodeId = j;
523  }
524 
525  if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
526  {
527  if (Block)
528  {
529  totalRunningTime += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime.QuadPart;
530  }
531  else
532  {
533  ULONG nodeIndex;
534 
535  nodeIndex = gpuAdapter->FirstNodeIndex + j;
536 
537  PhUpdateDelta(&EtGpuNodesTotalRunningTimeDelta[nodeIndex], queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart);
538 
539  if (RtlCheckBit(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j))
540  {
541  totalRunningTime += queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart;
542  systemRunningTime += queryStatistics.QueryResult.NodeInformation.SystemInformation.RunningTime.QuadPart;
543  }
544  }
545  }
546  }
547  }
548 
549  if (Block)
550  {
551  PhUpdateDelta(&Block->GpuRunningTimeDelta, totalRunningTime);
552  }
553  else
554  {
555  LARGE_INTEGER performanceCounter;
556 
557  NtQueryPerformanceCounter(&performanceCounter, &EtClockTotalRunningTimeFrequency);
558  PhUpdateDelta(&EtClockTotalRunningTimeDelta, performanceCounter.QuadPart);
559  PhUpdateDelta(&EtGpuTotalRunningTimeDelta, totalRunningTime);
560  PhUpdateDelta(&EtGpuSystemRunningTimeDelta, systemRunningTime);
561  }
562 }
563 
564 static VOID NTAPI ProcessesUpdatedCallback(
565  _In_opt_ PVOID Parameter,
566  _In_opt_ PVOID Context
567  )
568 {
569  static ULONG runCount = 0; // MUST keep in sync with runCount in process provider
570 
571  DOUBLE elapsedTime; // total GPU node elapsed time in micro-seconds
572  ULONG i;
573  PLIST_ENTRY listEntry;
574  FLOAT maxNodeValue = 0;
575  PET_PROCESS_BLOCK maxNodeBlock = NULL;
576 
577  // Update global statistics.
578 
579  EtpUpdateSegmentInformation(NULL);
580  EtpUpdateNodeInformation(NULL);
581 
582  elapsedTime = (DOUBLE)EtClockTotalRunningTimeDelta.Delta * 10000000 / EtClockTotalRunningTimeFrequency.QuadPart;
583 
584  if (elapsedTime != 0)
585  EtGpuNodeUsage = (FLOAT)(EtGpuTotalRunningTimeDelta.Delta / (elapsedTime * EtGpuNodeBitMapBitsSet));
586  else
587  EtGpuNodeUsage = 0;
588 
589  if (EtGpuNodeUsage > 1)
590  EtGpuNodeUsage = 1;
591 
592  // Do the update of the node bitmap if needed.
594  {
595  PULONG newBuffer;
596 
598 
599  if (newBuffer)
600  {
601  PhFree(EtGpuNodeBitMap.Buffer);
602  EtGpuNodeBitMap.Buffer = newBuffer;
603  EtGpuNodeBitMapBuffer = newBuffer;
604  EtGpuNodeBitMapBitsSet = RtlNumberOfSetBits(&EtGpuNodeBitMap);
606  }
607  }
608 
609  // Update per-process statistics.
610  // Note: no lock is needed because we only ever modify the list on this same thread.
611 
612  listEntry = EtProcessBlockListHead.Flink;
613 
614  while (listEntry != &EtProcessBlockListHead)
615  {
616  PET_PROCESS_BLOCK block;
617 
618  block = CONTAINING_RECORD(listEntry, ET_PROCESS_BLOCK, ListEntry);
619 
620  EtpUpdateSegmentInformation(block);
621  EtpUpdateNodeInformation(block);
622 
623  if (elapsedTime != 0)
624  {
625  block->GpuNodeUsage = (FLOAT)(block->GpuRunningTimeDelta.Delta / (elapsedTime * EtGpuNodeBitMapBitsSet));
626 
627  if (block->GpuNodeUsage > 1)
628  block->GpuNodeUsage = 1;
629  }
630 
631  if (maxNodeValue < block->GpuNodeUsage)
632  {
633  maxNodeValue = block->GpuNodeUsage;
634  maxNodeBlock = block;
635  }
636 
637  listEntry = listEntry->Flink;
638  }
639 
640  // Update history buffers.
641 
642  if (runCount != 0)
643  {
644  PhAddItemCircularBuffer_FLOAT(&EtGpuNodeHistory, EtGpuNodeUsage);
645  PhAddItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, (ULONG)(EtGpuDedicatedUsage / PAGE_SIZE));
646  PhAddItemCircularBuffer_ULONG(&EtGpuSharedHistory, (ULONG)(EtGpuSharedUsage / PAGE_SIZE));
647 
648  for (i = 0; i < EtGpuTotalNodeCount; i++)
649  {
650  FLOAT usage;
651 
652  usage = (FLOAT)(EtGpuNodesTotalRunningTimeDelta[i].Delta / elapsedTime);
653 
654  if (usage > 1)
655  usage = 1;
656 
657  PhAddItemCircularBuffer_FLOAT(&EtGpuNodesHistory[i], usage);
658  }
659 
660  if (maxNodeBlock)
661  {
662  PhAddItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, HandleToUlong(maxNodeBlock->ProcessItem->ProcessId));
663  PhAddItemCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, maxNodeBlock->GpuNodeUsage);
665  }
666  else
667  {
668  PhAddItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, 0);
669  PhAddItemCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, 0);
670  }
671  }
672 
673  runCount++;
674 }
675 
677  VOID
678  )
679 {
680  PPH_STRING string;
681 
682  string = PhBufferToHexString((PUCHAR)EtGpuNodeBitMapBuffer, BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount));
684  PhDereferenceObject(string);
685 }
686 
688  VOID
689  )
690 {
691  return EtpGpuAdapterList->Count;
692 }
693 
695  _In_ ULONG NodeIndex
696  )
697 {
698  ULONG i;
699  PETP_GPU_ADAPTER gpuAdapter;
700 
701  for (i = 0; i < EtpGpuAdapterList->Count; i++)
702  {
703  gpuAdapter = EtpGpuAdapterList->Items[i];
704 
705  if (NodeIndex >= gpuAdapter->FirstNodeIndex && NodeIndex < gpuAdapter->FirstNodeIndex + gpuAdapter->NodeCount)
706  return i;
707  }
708 
709  return -1;
710 }
711 
713  _In_ ULONG Index
714  )
715 {
716  PPH_STRING description;
717 
718  if (Index >= EtpGpuAdapterList->Count)
719  return NULL;
720 
721  description = ((PETP_GPU_ADAPTER)EtpGpuAdapterList->Items[Index])->Description;
722 
723  if (description)
724  {
725  PhReferenceObject(description);
726  return description;
727  }
728  else
729  {
730  return NULL;
731  }
732 }
733 
735  _Out_ PRTL_BITMAP BitMap
736  )
737 {
738  SIZE_T numberOfBytes;
739 
740  numberOfBytes = BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount);
741 
742  BitMap->Buffer = PhAllocate(numberOfBytes);
743  BitMap->SizeOfBitMap = EtGpuTotalNodeCount;
744  memset(BitMap->Buffer, 0, numberOfBytes);
745 }
746 
748  _In_ PRTL_BITMAP NewBitMap
749  )
750 {
751  PULONG buffer;
752 
753  buffer = _InterlockedExchangePointer(&EtGpuNewNodeBitMapBuffer, NewBitMap->Buffer);
754 
755  if (buffer)
756  PhFree(buffer);
757 }
758 
760  _In_ HANDLE ProcessHandle,
761  _Out_ PET_PROCESS_GPU_STATISTICS Statistics
762  )
763 {
764  NTSTATUS status;
765  ULONG i;
766  ULONG j;
767  PETP_GPU_ADAPTER gpuAdapter;
768  D3DKMT_QUERYSTATISTICS queryStatistics;
769 
770  memset(Statistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS));
771 
772  for (i = 0; i < EtpGpuAdapterList->Count; i++)
773  {
774  gpuAdapter = EtpGpuAdapterList->Items[i];
775 
776  Statistics->SegmentCount += gpuAdapter->SegmentCount;
777  Statistics->NodeCount += gpuAdapter->NodeCount;
778 
779  for (j = 0; j < gpuAdapter->SegmentCount; j++)
780  {
781  memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
783  queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
784  queryStatistics.hProcess = ProcessHandle;
785  queryStatistics.QueryProcessSegment.SegmentId = j;
786 
787  if (NT_SUCCESS(status = D3DKMTQueryStatistics_I(&queryStatistics)))
788  {
789  ULONG64 bytesCommitted;
790 
791  if (WindowsVersion >= WINDOWS_8)
792  {
793  bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted;
794  }
795  else
796  {
797  bytesCommitted = (ULONG)queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted;
798  }
799 
800  if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j))
801  Statistics->SharedCommitted += bytesCommitted;
802  else
803  Statistics->DedicatedCommitted += bytesCommitted;
804  }
805  }
806 
807  for (j = 0; j < gpuAdapter->NodeCount; j++)
808  {
809  memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
810  queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_NODE;
811  queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
812  queryStatistics.hProcess = ProcessHandle;
813  queryStatistics.QueryProcessNode.NodeId = j;
814 
815  if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
816  {
817  Statistics->RunningTime += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime.QuadPart;
818  Statistics->ContextSwitches += queryStatistics.QueryResult.ProcessNodeInformation.ContextSwitch;
819  }
820  }
821 
822  memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
823  queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS;
824  queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
825  queryStatistics.hProcess = ProcessHandle;
826 
827  if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
828  {
829  Statistics->BytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.BytesAllocated;
830  Statistics->BytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.BytesReserved;
831  Statistics->WriteCombinedBytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.WriteCombinedBytesAllocated;
832  Statistics->WriteCombinedBytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.WriteCombinedBytesReserved;
833  Statistics->CachedBytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.CachedBytesAllocated;
834  Statistics->CachedBytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.CachedBytesReserved;
835  Statistics->SectionBytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.SectionBytesAllocated;
836  Statistics->SectionBytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.SectionBytesReserved;
837  }
838  }
839 }