Adds UMA histograms for pipeline compilations in Dawn.

- Updates Vulkan/D3D12 backends for cache hit/miss metrics.

Bugs: dawn:1934
Change-Id: Ifcb38c16ea2a67fd3c47a6b0c81dbba5c5f83d71
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/142980
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Loko Kung <lokokung@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/d3d12/ComputePipelineD3D12.cpp b/src/dawn/native/d3d12/ComputePipelineD3D12.cpp
index 6b962a5..8dbf5bd 100644
--- a/src/dawn/native/d3d12/ComputePipelineD3D12.cpp
+++ b/src/dawn/native/d3d12/ComputePipelineD3D12.cpp
@@ -25,6 +25,7 @@
 #include "dawn/native/d3d12/PlatformFunctionsD3D12.h"
 #include "dawn/native/d3d12/ShaderModuleD3D12.h"
 #include "dawn/native/d3d12/UtilsD3D12.h"
+#include "dawn/platform/metrics/HistogramMacros.h"
 
 namespace dawn::native::d3d12 {
 
@@ -76,7 +77,10 @@
         d3dDesc.CachedPSO.CachedBlobSizeInBytes = blob.Size();
     }
 
+    // We don't use the scoped cache histogram counters for the cache hit here so that we can
+    // condition on whether it fails appropriately.
     auto* d3d12Device = device->GetD3D12Device();
+    platform::metrics::DawnHistogramTimer cacheTimer(device->GetPlatform());
     HRESULT result =
         d3d12Device->CreateComputePipelineState(&d3dDesc, IID_PPV_ARGS(&mPipelineState));
     if (cacheHit && result == D3D12_ERROR_DRIVER_VERSION_MISMATCH) {
@@ -84,16 +88,20 @@
         cacheHit = false;
         d3dDesc.CachedPSO.pCachedBlob = nullptr;
         d3dDesc.CachedPSO.CachedBlobSizeInBytes = 0;
+        cacheTimer.Reset();
         result = d3d12Device->CreateComputePipelineState(&d3dDesc, IID_PPV_ARGS(&mPipelineState));
     }
     DAWN_TRY(CheckHRESULT(result, "D3D12 creating pipeline state"));
 
     if (!cacheHit) {
         // Cache misses, need to get pipeline cached blob and store.
+        cacheTimer.RecordMicroseconds("D3D12.CreateComputePipelineState.CacheMiss");
         ComPtr<ID3DBlob> d3dBlob;
         DAWN_TRY(CheckHRESULT(GetPipelineState()->GetCachedBlob(&d3dBlob),
                               "D3D12 compute pipeline state get cached blob"));
         device->StoreCachedBlob(GetCacheKey(), CreateBlob(std::move(d3dBlob)));
+    } else {
+        cacheTimer.RecordMicroseconds("D3D12.CreateComputePipelineState.CacheHit");
     }
 
     SetLabelImpl();
diff --git a/src/dawn/native/d3d12/RenderPipelineD3D12.cpp b/src/dawn/native/d3d12/RenderPipelineD3D12.cpp
index 0c87835d..9b10ecc 100644
--- a/src/dawn/native/d3d12/RenderPipelineD3D12.cpp
+++ b/src/dawn/native/d3d12/RenderPipelineD3D12.cpp
@@ -30,6 +30,7 @@
 #include "dawn/native/d3d12/ShaderModuleD3D12.h"
 #include "dawn/native/d3d12/TextureD3D12.h"
 #include "dawn/native/d3d12/UtilsD3D12.h"
+#include "dawn/platform/metrics/HistogramMacros.h"
 
 namespace dawn::native::d3d12 {
 namespace {
@@ -411,24 +412,32 @@
         descriptorD3D12.CachedPSO.CachedBlobSizeInBytes = blob.Size();
     }
 
-    HRESULT result = device->GetD3D12Device()->CreateGraphicsPipelineState(
-        &descriptorD3D12, IID_PPV_ARGS(&mPipelineState));
+    // We don't use the scoped cache histogram counters for the cache hit here so that we can
+    // condition on whether it fails appropriately.
+    auto* d3d12Device = device->GetD3D12Device();
+    platform::metrics::DawnHistogramTimer cacheTimer(device->GetPlatform());
+    HRESULT result =
+        d3d12Device->CreateGraphicsPipelineState(&descriptorD3D12, IID_PPV_ARGS(&mPipelineState));
     if (cacheHit && result == D3D12_ERROR_DRIVER_VERSION_MISMATCH) {
         // See dawn:1878 where it is possible for the PSO creation to fail with this error.
         cacheHit = false;
         descriptorD3D12.CachedPSO.pCachedBlob = nullptr;
         descriptorD3D12.CachedPSO.CachedBlobSizeInBytes = 0;
-        result = device->GetD3D12Device()->CreateGraphicsPipelineState(
-            &descriptorD3D12, IID_PPV_ARGS(&mPipelineState));
+        cacheTimer.Reset();
+        result = d3d12Device->CreateGraphicsPipelineState(&descriptorD3D12,
+                                                          IID_PPV_ARGS(&mPipelineState));
     }
     DAWN_TRY(CheckHRESULT(result, "D3D12 create graphics pipeline state"));
 
     if (!cacheHit) {
         // Cache misses, need to get pipeline cached blob and store.
+        cacheTimer.RecordMicroseconds("D3D12.CreateGraphicsPipelineState.CacheMiss");
         ComPtr<ID3DBlob> d3dBlob;
         DAWN_TRY(CheckHRESULT(GetPipelineState()->GetCachedBlob(&d3dBlob),
                               "D3D12 render pipeline state get cached blob"));
         device->StoreCachedBlob(GetCacheKey(), CreateBlob(std::move(d3dBlob)));
+    } else {
+        cacheTimer.RecordMicroseconds("D3D12.CreateGraphicsPipelineState.CacheHit");
     }
 
     SetLabelImpl();
diff --git a/src/dawn/native/vulkan/ComputePipelineVk.cpp b/src/dawn/native/vulkan/ComputePipelineVk.cpp
index f607f7b..88cf7c4 100644
--- a/src/dawn/native/vulkan/ComputePipelineVk.cpp
+++ b/src/dawn/native/vulkan/ComputePipelineVk.cpp
@@ -26,6 +26,7 @@
 #include "dawn/native/vulkan/ShaderModuleVk.h"
 #include "dawn/native/vulkan/UtilsVulkan.h"
 #include "dawn/native/vulkan/VulkanError.h"
+#include "dawn/platform/metrics/HistogramMacros.h"
 
 namespace dawn::native::vulkan {
 
@@ -86,11 +87,22 @@
              stream::Iterable(moduleAndSpirv.spirv, moduleAndSpirv.wordCount));
 
     // Try to see if we have anything in the blob cache.
+    platform::metrics::DawnHistogramTimer cacheTimer(GetDevice()->GetPlatform());
     Ref<PipelineCache> cache = ToBackend(GetDevice()->GetOrCreatePipelineCache(GetCacheKey()));
-    DAWN_TRY(
-        CheckVkSuccess(device->fn.CreateComputePipelines(device->GetVkDevice(), cache->GetHandle(),
-                                                         1, &createInfo, nullptr, &*mHandle),
-                       "CreateComputePipeline"));
+    if (cache->CacheHit()) {
+        DAWN_TRY(CheckVkSuccess(
+            device->fn.CreateComputePipelines(device->GetVkDevice(), cache->GetHandle(), 1,
+                                              &createInfo, nullptr, &*mHandle),
+            "CreateComputePipelines"));
+        cacheTimer.RecordMicroseconds("Vulkan.CreateComputePipelines.CacheHit");
+    } else {
+        cacheTimer.Reset();
+        DAWN_TRY(CheckVkSuccess(
+            device->fn.CreateComputePipelines(device->GetVkDevice(), cache->GetHandle(), 1,
+                                              &createInfo, nullptr, &*mHandle),
+            "CreateComputePipelines"));
+        cacheTimer.RecordMicroseconds("Vulkan.CreateComputePipelines.CacheMiss");
+    }
     // TODO(dawn:549): Flush is currently in the same thread, but perhaps deferrable.
     DAWN_TRY(cache->FlushIfNeeded());
 
diff --git a/src/dawn/native/vulkan/RenderPipelineVk.cpp b/src/dawn/native/vulkan/RenderPipelineVk.cpp
index 448ef73..d6713f9 100644
--- a/src/dawn/native/vulkan/RenderPipelineVk.cpp
+++ b/src/dawn/native/vulkan/RenderPipelineVk.cpp
@@ -28,6 +28,7 @@
 #include "dawn/native/vulkan/TextureVk.h"
 #include "dawn/native/vulkan/UtilsVulkan.h"
 #include "dawn/native/vulkan/VulkanError.h"
+#include "dawn/platform/metrics/HistogramMacros.h"
 
 namespace dawn::native::vulkan {
 
@@ -558,11 +559,23 @@
     StreamIn(&mCacheKey, createInfo, layout->GetCacheKey());
 
     // Try to see if we have anything in the blob cache.
+    platform::metrics::DawnHistogramTimer cacheTimer(GetDevice()->GetPlatform());
     Ref<PipelineCache> cache = ToBackend(GetDevice()->GetOrCreatePipelineCache(GetCacheKey()));
-    DAWN_TRY(
-        CheckVkSuccess(device->fn.CreateGraphicsPipelines(device->GetVkDevice(), cache->GetHandle(),
-                                                          1, &createInfo, nullptr, &*mHandle),
-                       "CreateGraphicsPipelines"));
+    if (cache->CacheHit()) {
+        DAWN_TRY(CheckVkSuccess(
+            device->fn.CreateGraphicsPipelines(device->GetVkDevice(), cache->GetHandle(), 1,
+                                               &createInfo, nullptr, &*mHandle),
+            "CreateGraphicsPipelines"));
+        cacheTimer.RecordMicroseconds("Vulkan.CreateGraphicsPipelines.CacheHit");
+    } else {
+        cacheTimer.Reset();
+        DAWN_TRY(CheckVkSuccess(
+            device->fn.CreateGraphicsPipelines(device->GetVkDevice(), cache->GetHandle(), 1,
+                                               &createInfo, nullptr, &*mHandle),
+            "CreateGraphicsPipelines"));
+        cacheTimer.RecordMicroseconds("Vulkan.CreateGraphicsPipelines.CacheMiss");
+    }
+
     // TODO(dawn:549): Flush is currently in the same thread, but perhaps deferrable.
     DAWN_TRY(cache->FlushIfNeeded());