Bug 1743176 - Collect the GPU time used in the parent process through Glean, r=chutten,jrmuizel.

Differential Revision: https://phabricator.services.mozilla.com/D132265
This commit is contained in:
Florian Quèze 2021-11-30 21:07:28 +00:00
Родитель 464abfcf25
Коммит 15f070e21c
9 изменённых файлов: 144 добавлений и 13 удалений

Просмотреть файл

@ -19,8 +19,9 @@ typedef struct _D3DKMTQS_COUNTER {
typedef struct _D3DKMTQS_ADAPTER_INFO {
ULONG NbSegments;
ULONG NodeCount;
ULONG Filler[4];
ULONG Filler[3];
ULONGLONG Filler2[2]; // Assumed sizeof(LONGLONG) = sizeof(ULONGLONG)
struct {
ULONG Filler[14];
@ -121,11 +122,20 @@ typedef struct _D3DKMTQS_PROCESS_SEGMENT_INFO {
ULONG64 Reserved[8];
} D3DKMTQS_PROCESS_SEGMENT_INFO;
typedef struct _D3DKMTQS_PROCESS_NODE_INFO {
LARGE_INTEGER RunningTime; // 100ns
ULONG ContextSwitch;
ULONG PreemptionStatistics[16];
ULONG PacketStatistics[32];
ULONG64 Reserved[8];
} D3DKMTQS_PROCESS_NODE_INFO;
typedef enum _D3DKMTQS_TYPE {
D3DKMTQS_ADAPTER = 0,
D3DKMTQS_PROCESS = 1,
D3DKMTQS_SEGMENT = 3,
D3DKMTQS_PROCESS_SEGMENT = 4,
D3DKMTQS_PROCESS_NODE = 6,
} D3DKMTQS_TYPE;
typedef union _D3DKMTQS_RESULT {
@ -134,12 +144,17 @@ typedef union _D3DKMTQS_RESULT {
D3DKMTQS_SEGMENT_INFO_WIN8 SegmentInfoWin8;
D3DKMTQS_PROCESS_INFO ProcessInfo;
D3DKMTQS_PROCESS_SEGMENT_INFO ProcessSegmentInfo;
D3DKMTQS_PROCESS_NODE_INFO ProcessNodeInformation;
} D3DKMTQS_RESULT;
typedef struct _D3DKMTQS_QUERY_SEGMENT {
ULONG SegmentId;
} D3DKMTQS_QUERY_SEGMENT;
typedef struct _D3DKMTQS_QUERY_NODE {
ULONG NodeId;
} D3DKMTQS_QUERY_NODE;
typedef struct _D3DKMTQS {
D3DKMTQS_TYPE Type;
LUID AdapterLuid;
@ -149,6 +164,7 @@ typedef struct _D3DKMTQS {
union {
D3DKMTQS_QUERY_SEGMENT QuerySegment;
D3DKMTQS_QUERY_SEGMENT QueryProcessSegment;
D3DKMTQS_QUERY_NODE QueryProcessNode;
};
} D3DKMTQS;

Просмотреть файл

@ -313,6 +313,69 @@ void gfxWindowsPlatform::InitMemoryReportersForGPUProcess() {
RegisterStrongMemoryReporter(new D3DSharedTexturesReporter());
}
/* static */
nsresult gfxWindowsPlatform::GetGpuTimeSinceProcessStartInMs(
uint64_t* aResult) {
RefPtr<ID3D11Device> d3d11Device;
if (!(d3d11Device = mozilla::gfx::Factory::GetDirect3D11Device())) {
// If we don't have a D3DDevice, we likely didn't use any GPU time.
*aResult = 0;
return NS_OK;
}
nsModuleHandle module(LoadLibrary(L"gdi32.dll"));
if (!module) {
return NS_ERROR_NOT_AVAILABLE;
}
PFND3DKMTQS queryD3DKMTStatistics =
(PFND3DKMTQS)GetProcAddress(module, "D3DKMTQueryStatistics");
if (!queryD3DKMTStatistics) {
return NS_ERROR_NOT_AVAILABLE;
}
RefPtr<IDXGIDevice> dxgiDevice;
if (d3d11Device->QueryInterface(__uuidof(IDXGIDevice),
getter_AddRefs(dxgiDevice)) != S_OK) {
return NS_ERROR_FAILURE;
}
IDXGIAdapter* DXGIAdapter;
if (dxgiDevice->GetAdapter(&DXGIAdapter) != S_OK) {
return NS_ERROR_FAILURE;
}
DXGI_ADAPTER_DESC adapterDesc;
DXGIAdapter->GetDesc(&adapterDesc);
DXGIAdapter->Release();
D3DKMTQS queryStatistics;
memset(&queryStatistics, 0, sizeof(D3DKMTQS));
queryStatistics.Type = D3DKMTQS_ADAPTER;
queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
if (!NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
return NS_ERROR_FAILURE;
}
uint64_t result = 0;
ULONG nodeCount = queryStatistics.QueryResult.AdapterInfo.NodeCount;
for (ULONG i = 0; i < nodeCount; ++i) {
memset(&queryStatistics, 0, sizeof(D3DKMTQS));
queryStatistics.Type = D3DKMTQS_PROCESS_NODE;
queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
queryStatistics.hProcess = GetCurrentProcess();
queryStatistics.QueryProcessNode.NodeId = i;
if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
result += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime
.QuadPart *
100 / PR_NSEC_PER_MSEC;
}
}
*aResult = result;
return NS_OK;
}
static void UpdateANGLEConfig() {
if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
gfxConfig::Disable(Feature::D3D11_HW_ANGLE, FeatureStatus::Disabled,

Просмотреть файл

@ -6,12 +6,6 @@
#ifndef GFX_WINDOWS_PLATFORM_H
#define GFX_WINDOWS_PLATFORM_H
/**
* XXX to get CAIRO_HAS_DWRITE_FONT
* and cairo_win32_scaled_font_select_font
*/
#include "cairo-win32.h"
#include "gfxCrashReporterUtils.h"
#include "gfxFontUtils.h"
#include "gfxWindowsSurface.h"
@ -177,6 +171,8 @@ class gfxWindowsPlatform final : public gfxPlatform {
}
public:
static nsresult GetGpuTimeSinceProcessStartInMs(uint64_t* aResult);
bool DwmCompositionEnabled();
mozilla::layers::ReadbackManagerD3D11* GetReadbackManager();

Просмотреть файл

@ -21,8 +21,8 @@ using FlushFOGDataPromise = mozilla::dom::ContentParent::FlushFOGDataPromise;
namespace mozilla {
namespace glean {
static void RecordCpuTime() {
static uint64_t previousCpuTime = 0;
static void RecordPowerMetrics() {
static uint64_t previousCpuTime = 0, previousGpuTime = 0;
uint64_t cpuTime;
if (NS_FAILED(GetCpuTimeSinceProcessStartInMs(&cpuTime))) {
@ -38,6 +38,16 @@ static void RecordCpuTime() {
// This should be fine for now, but may overflow in the future.
power::total_cpu_time_ms.Add(int32_t(newCpuTime));
}
uint64_t gpuTime;
if (NS_SUCCEEDED(GetGpuTimeSinceProcessStartInMs(&gpuTime))) {
uint64_t newGpuTime = gpuTime - previousGpuTime;
previousGpuTime += newGpuTime;
if (newGpuTime) {
power::total_gpu_time_ms.Add(int32_t(newGpuTime));
}
}
}
/**
@ -48,8 +58,8 @@ static void RecordCpuTime() {
* serialized payload that the Rust impl hands you.
*/
void FlushFOGData(std::function<void(ipc::ByteBuf&&)>&& aResolver) {
// Record the CPU time right before data is sent to the parent.
RecordCpuTime();
// Record power metrics right before data is sent to the parent.
RecordPowerMetrics();
ByteBuf buf;
uint32_t ipcBufferSize = impl::fog_serialize_ipc_buf();
@ -130,8 +140,9 @@ void SendFOGData(ipc::ByteBuf&& buf) {
* sending it all down into Rust to be used.
*/
RefPtr<GenericPromise> FlushAndUseFOGData() {
// Record CPU time on the parent before sending requests to child processes.
RecordCpuTime();
// Record power metrics on the parent before sending requests to child
// processes.
RecordPowerMetrics();
RefPtr<GenericPromise::Private> ret = new GenericPromise::Private(__func__);
std::function<void(nsTArray<ByteBuf> &&)> resolver =

Просмотреть файл

@ -27,6 +27,13 @@ class GeckoChildProcessHost;
*/
nsresult GetCpuTimeSinceProcessStartInMs(uint64_t* aResult);
/**
* Return the number of milliseconds of GPU time used since process start.
*
* @return NS_OK on success.
*/
nsresult GetGpuTimeSinceProcessStartInMs(uint64_t* aResult);
// Process types. When updating this enum, please make sure to update
// WebIDLProcType, ChromeUtils::RequestProcInfo and ProcTypeToWebIDL to
// mirror the changes.

Просмотреть файл

@ -31,6 +31,19 @@ nsresult GetCpuTimeSinceProcessStartInMs(uint64_t* aResult) {
return NS_OK;
}
nsresult GetGpuTimeSinceProcessStartInMs(uint64_t* aResult) {
task_power_info_v2_data_t task_power_info;
mach_msg_type_number_t count = TASK_POWER_INFO_V2_COUNT;
kern_return_t kr =
task_info(mach_task_self(), TASK_POWER_INFO_V2, (task_info_t)&task_power_info, &count);
if (kr != KERN_SUCCESS) {
return NS_ERROR_FAILURE;
}
*aResult = task_power_info.gpu_energy.task_gpu_utilisation / PR_NSEC_PER_MSEC;
return NS_OK;
}
RefPtr<ProcInfoPromise> GetProcInfo(nsTArray<ProcInfoRequest>&& aRequests) {
auto holder = MakeUnique<MozPromiseHolder<ProcInfoPromise>>();
RefPtr<ProcInfoPromise> promise = holder->Ensure(__func__);

Просмотреть файл

@ -196,6 +196,10 @@ nsresult GetCpuTimeSinceProcessStartInMs(uint64_t* aResult) {
return NS_OK;
}
nsresult GetGpuTimeSinceProcessStartInMs(uint64_t* aResult) {
return NS_ERROR_NOT_IMPLEMENTED;
}
RefPtr<ProcInfoPromise> GetProcInfo(nsTArray<ProcInfoRequest>&& aRequests) {
auto holder = MakeUnique<MozPromiseHolder<ProcInfoPromise>>();
RefPtr<ProcInfoPromise> promise = holder->Ensure(__func__);

Просмотреть файл

@ -7,6 +7,7 @@
#include "mozilla/ProcInfo.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/SSE.h"
#include "gfxWindowsPlatform.h"
#include "nsMemoryReporterManager.h"
#include "nsNetCID.h"
#include "nsWindowsHelpers.h"
@ -85,6 +86,10 @@ nsresult GetCpuTimeSinceProcessStartInMs(uint64_t* aResult) {
return NS_OK;
}
nsresult GetGpuTimeSinceProcessStartInMs(uint64_t* aResult) {
return gfxWindowsPlatform::GetGpuTimeSinceProcessStartInMs(aResult);
}
RefPtr<ProcInfoPromise> GetProcInfo(nsTArray<ProcInfoRequest>&& aRequests) {
auto holder = MakeUnique<MozPromiseHolder<ProcInfoPromise>>();
RefPtr<ProcInfoPromise> promise = holder->Ensure(__func__);

Просмотреть файл

@ -26,3 +26,19 @@ power:
notification_emails:
- florian@mozilla.com
expires: never
total_gpu_time_ms:
type: counter
description: >
Total GPU time used by all processes in ms.
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1743176
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1743176
data_sensitivity:
- technical
notification_emails:
- florian@mozilla.com
expires: never
no_lint:
- COMMON_PREFIX