perf tests: Record perf counter metrics.
This adds a new command line argument that will allow the user to
specify perf counters to record into the test output.
Bug: angleproject:4918
Change-Id: Ia7432ff96eadf13ef681f67d2d503d00fd83e06e
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3516970
Reviewed-by: Lingfeng Yang <lfy@google.com>
Reviewed-by: Charlie Lao <cclao@google.com>
Reviewed-by: Yuxin Hu <yuxinhu@google.com>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/common/angleutils.h b/src/common/angleutils.h
index dd70f4f..06d412b 100644
--- a/src/common/angleutils.h
+++ b/src/common/angleutils.h
@@ -90,6 +90,8 @@
};
// AMD_performance_monitor helpers.
+constexpr char kPerfMonitorExtensionName[] = "GL_AMD_performance_monitor";
+
struct PerfMonitorCounter
{
PerfMonitorCounter();
diff --git a/src/tests/gl_tests/VulkanPerformanceCounterTest.cpp b/src/tests/gl_tests/VulkanPerformanceCounterTest.cpp
index 13ab895..c9d0735 100644
--- a/src/tests/gl_tests/VulkanPerformanceCounterTest.cpp
+++ b/src/tests/gl_tests/VulkanPerformanceCounterTest.cpp
@@ -18,62 +18,12 @@
#include "test_utils/gl_raii.h"
#include "util/random_utils.h"
+#include "util/shader_utils.h"
using namespace angle;
namespace
{
-constexpr char kExtensionName[] = "GL_AMD_performance_monitor";
-
-using CounterNameToIndexMap = std::map<std::string, GLuint>;
-
-CounterNameToIndexMap BuildCounterNameToIndexMap()
-{
- GLint numCounters = 0;
- glGetPerfMonitorCountersAMD(0, &numCounters, nullptr, 0, nullptr);
- EXPECT_GL_NO_ERROR();
-
- std::vector<GLuint> counterIndexes(numCounters, 0);
- glGetPerfMonitorCountersAMD(0, nullptr, nullptr, numCounters, counterIndexes.data());
- EXPECT_GL_NO_ERROR();
-
- CounterNameToIndexMap indexMap;
-
- for (GLuint counterIndex : counterIndexes)
- {
- static constexpr size_t kBufSize = 1000;
- char buffer[kBufSize] = {};
- glGetPerfMonitorCounterStringAMD(0, counterIndex, kBufSize, nullptr, buffer);
- EXPECT_GL_NO_ERROR();
-
- indexMap[buffer] = counterIndex;
- }
-
- return indexMap;
-}
-
-void UpdatePerfCounter(const CounterNameToIndexMap &counterIndexMap,
- GLuint *counterOut,
- const char *name,
- std::vector<angle::PerfMonitorTriplet> &triplets)
-{
- auto iter = counterIndexMap.find(name);
- ASSERT(iter != counterIndexMap.end());
- GLuint counterIndex = iter->second;
-
- for (const angle::PerfMonitorTriplet &triplet : triplets)
- {
- ASSERT(triplet.group == 0);
- if (triplet.counter == counterIndex)
- {
- *counterOut = triplet.value;
- return;
- }
- }
-
- UNREACHABLE();
-}
-
class VulkanPerformanceCounterTest : public ANGLETest
{
protected:
@@ -213,33 +163,12 @@
angle::VulkanPerfCounters getPerfCounters()
{
- GLuint resultSize = 0;
- glGetPerfMonitorCounterDataAMD(0, GL_PERFMON_RESULT_SIZE_AMD, sizeof(GLuint), &resultSize,
- nullptr);
- EXPECT_GL_NO_ERROR();
- EXPECT_GT(resultSize, 0u);
-
- std::vector<angle::PerfMonitorTriplet> perfResults(resultSize /
- sizeof(angle::PerfMonitorTriplet));
- glGetPerfMonitorCounterDataAMD(0, GL_PERFMON_RESULT_AMD,
- perfResults.size() * sizeof(perfResults[0]),
- &perfResults.data()->group, nullptr);
-
if (mIndexMap.empty())
{
mIndexMap = BuildCounterNameToIndexMap();
}
- angle::VulkanPerfCounters counters;
-
-#define ANGLE_UNPACK_PERF_COUNTER(COUNTER) \
- UpdatePerfCounter(mIndexMap, &counters.COUNTER, #COUNTER, perfResults);
-
- ANGLE_VK_PERF_COUNTERS_X(ANGLE_UNPACK_PERF_COUNTER)
-
-#undef ANGLE_UNPACK_PERF_COUNTER
-
- return counters;
+ return GetPerfCounters(mIndexMap);
}
CounterNameToIndexMap mIndexMap;
@@ -261,7 +190,7 @@
// Tests that texture updates to unused textures don't break the RP.
TEST_P(VulkanPerformanceCounterTest, NewTextureDoesNotBreakRenderPass)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
GLColor kInitialData[4] = {GLColor::red, GLColor::blue, GLColor::green, GLColor::yellow};
@@ -311,7 +240,7 @@
// Tests that RGB texture should not break renderpass.
TEST_P(VulkanPerformanceCounterTest, SampleFromRGBTextureDoesNotBreakRenderPass)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
glUseProgram(program);
@@ -354,7 +283,7 @@
// Tests that RGB texture should not break renderpass.
TEST_P(VulkanPerformanceCounterTest, RenderToRGBTextureDoesNotBreakRenderPass)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::UniformColor());
glUseProgram(program);
@@ -393,7 +322,7 @@
// Tests that changing a Texture's max level hits the descriptor set cache.
TEST_P(VulkanPerformanceCounterTest, ChangingMaxLevelHitsDescriptorCache)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
GLColor kInitialData[4] = {GLColor::red, GLColor::blue, GLColor::green, GLColor::yellow};
@@ -445,7 +374,7 @@
// Tests that two glCopyBufferSubData commands can share a barrier.
TEST_P(VulkanPerformanceCounterTest, IndependentBufferCopiesShareSingleBarrier)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
constexpr GLint srcDataA[] = {1, 2, 3, 4};
constexpr GLint srcDataB[] = {5, 6, 7, 8};
@@ -491,7 +420,7 @@
// used
TEST_P(VulkanPerformanceCounterTest_ES31, MultisampleResolveWithBlit)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
constexpr int kSize = 16;
glViewport(0, 0, kSize, kSize);
@@ -544,7 +473,7 @@
// Ensures a read-only depth-stencil feedback loop works in a single RenderPass.
TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthStencilFeedbackLoopUsesSingleRenderPass)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
constexpr GLsizei kSize = 4;
@@ -634,7 +563,7 @@
// - Scenario: invalidate, disable, draw
TEST_P(VulkanPerformanceCounterTest, InvalidateDisableDraw)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
@@ -682,7 +611,7 @@
// - Scenario: disable, invalidate, draw
TEST_P(VulkanPerformanceCounterTest, DisableInvalidateDraw)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
@@ -730,7 +659,7 @@
// - Scenario: disable, draw, invalidate, enable
TEST_P(VulkanPerformanceCounterTest, DisableDrawInvalidateEnable)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
@@ -789,7 +718,7 @@
// - Scenario: invalidate
TEST_P(VulkanPerformanceCounterTest, Invalidate)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
@@ -828,7 +757,7 @@
// whole framebuffer.
TEST_P(VulkanPerformanceCounterTest, InvalidateSub)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
@@ -869,7 +798,7 @@
// - Scenario: invalidate, draw
TEST_P(VulkanPerformanceCounterTest, InvalidateDraw)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
@@ -913,7 +842,7 @@
// - Scenario: invalidate, draw, disable
TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisable)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
// http://anglebug.com/6857
ANGLE_SKIP_TEST_IF(IsLinux() && IsAMD() && IsVulkan());
@@ -967,7 +896,7 @@
// - Scenario: invalidate, disable, draw, enable
TEST_P(VulkanPerformanceCounterTest, InvalidateDisableDrawEnable)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+0), stencil(Clears+0, Load+0, Stores+0)
@@ -1020,7 +949,7 @@
// - Scenario: invalidate, disable, draw, enable, draw
TEST_P(VulkanPerformanceCounterTest, InvalidateDisableDrawEnableDraw)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+0, Stores+0)
@@ -1075,7 +1004,7 @@
// - Scenario: invalidate, draw, disable, enable
TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisableEnable)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+0, Stores+0)
@@ -1131,7 +1060,7 @@
// - Scenario: invalidate, draw, disable, enable, invalidate
TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisableEnableInvalidate)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+0), stencil(Clears+0, Load+0, Stores+0)
@@ -1189,7 +1118,7 @@
// - Scenario: invalidate, draw, disable, enable, invalidate, draw
TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisableEnableInvalidateDraw)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+0, Stores+0)
@@ -1251,7 +1180,7 @@
// - Scenario: invalidate, disable, enable, draw
TEST_P(VulkanPerformanceCounterTest, InvalidateDisableEnableDraw)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+0, Stores+0)
@@ -1303,7 +1232,7 @@
// Tests that an in renderpass clear after invalidate keeps content stored.
TEST_P(VulkanPerformanceCounterTest, InvalidateAndClear)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+0, Stores+0)
@@ -1353,7 +1282,7 @@
// content stored.
TEST_P(VulkanPerformanceCounterTest, InvalidateAndMaskedClear)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+1, Load+0, Stores+1)
@@ -1414,7 +1343,7 @@
// - Scenario: invalidate, detach D/S texture and modify it, attach D/S texture, draw with blend
TEST_P(VulkanPerformanceCounterTest, InvalidateDetachModifyTexAttachDrawWithBlend)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+0, Stores+1)
@@ -1504,7 +1433,7 @@
// - Scenario: invalidate
TEST_P(VulkanPerformanceCounterTest, InvalidateDrawAndDeleteRenderbuffer)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+1), stencil(Clears+0, Load+0, Stores+0)
@@ -1549,7 +1478,7 @@
// Tests that even if the app clears depth, it should be invalidated if there is no read.
TEST_P(VulkanPerformanceCounterTest, SwapShouldInvalidateDepthAfterClear)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
@@ -1574,7 +1503,7 @@
// Tests that masked color clears don't break the RP.
TEST_P(VulkanPerformanceCounterTest, MaskedColorClearDoesNotBreakRenderPass)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
@@ -1614,7 +1543,7 @@
// Tests that masked color/depth/stencil clears don't break the RP.
TEST_P(VulkanPerformanceCounterTest, MaskedClearDoesNotBreakRenderPass)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
constexpr GLsizei kSize = 64;
@@ -1695,7 +1624,7 @@
// Tests that clear followed by scissored draw uses loadOp to clear.
TEST_P(VulkanPerformanceCounterTest, ClearThenScissoredDraw)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
uint32_t expectedRenderPassCount = getPerfCounters().renderPasses + 1;
uint32_t expectedDepthClears = getPerfCounters().depthClears + 1;
@@ -1768,7 +1697,7 @@
// Tests that scissored clears don't break the RP.
TEST_P(VulkanPerformanceCounterTest, ScissoredClearDoesNotBreakRenderPass)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
constexpr GLsizei kSize = 64;
@@ -1866,7 +1795,7 @@
// Tests that draw buffer change with all color channel mask off should not break renderpass
TEST_P(VulkanPerformanceCounterTest, DrawbufferChangeWithAllColorMaskDisabled)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::UniformColor());
glUseProgram(program);
@@ -1925,7 +1854,7 @@
// Tests the optimization that a glFlush call issued inside a renderpass will be skipped.
TEST_P(VulkanPerformanceCounterTest, InRenderpassFlushShouldNotBreakRenderpass)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
uint32_t expectedRenderPassCount = getPerfCounters().renderPasses + 1;
GLTexture texture;
@@ -1952,7 +1881,7 @@
// Tests that depth/stencil texture clear/load works correctly.
TEST_P(VulkanPerformanceCounterTest, DepthStencilTextureClearAndLoad)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
// TODO: http://anglebug.com/5329 Flaky test
ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
@@ -2065,7 +1994,7 @@
// Tests that multisampled-render-to-texture depth/stencil textures don't ever load data.
TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilTextureShouldNotLoad)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
// http://anglebug.com/5083
ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
@@ -2193,7 +2122,7 @@
ANGLE_SKIP_TEST_IF(IsWindows7() && IsNVIDIA() && IsVulkan());
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
@@ -2316,7 +2245,7 @@
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
@@ -2442,7 +2371,7 @@
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
// Expect rpCount+1, no depth/stencil clear, load or store.
@@ -2508,7 +2437,7 @@
// Ensures we use read-only depth layout when there is no write
TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthBufferLayout)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
constexpr GLsizei kSize = 64;
@@ -2577,7 +2506,7 @@
// invalidate)
TEST_P(VulkanPerformanceCounterTest, RenderPassAfterRenderPassWithoutDepthStencilWrite)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
// Expect rpCount+1, depth(Clears+0, Loads+0, Stores+0), stencil(Clears+0, Load+0, Stores+0)
@@ -2636,7 +2565,7 @@
// etc) don't break the render pass.
TEST_P(VulkanPerformanceCounterTest, ClearAfterClearDoesNotBreakRenderPass)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
uint32_t expectedRenderPassCount = getPerfCounters().renderPasses + 1;
constexpr GLsizei kSize = 6;
@@ -2780,7 +2709,7 @@
// Ensures that changing the scissor size doesn't break the render pass.
TEST_P(VulkanPerformanceCounterTest, ScissorDoesNotBreakRenderPass)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
constexpr GLsizei kSize = 16;
@@ -3026,7 +2955,7 @@
// Tests that changing UBO bindings does not allocate new descriptor sets.
TEST_P(VulkanPerformanceCounterTest, ChangingUBOsHitsDescriptorSetCache)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
// Set up two UBOs, one filled with "1" and the second with "2".
constexpr GLsizei kCount = 64;
@@ -3155,7 +3084,7 @@
// waiting for the GPU access to complete before returning a pointer to the buffer.
TEST_P(VulkanPerformanceCounterTest, MappingGpuReadOnlyBufferGhostsBuffer)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
// 1. Create a buffer, map it, fill it with red
// 2. Draw with buffer (GPU read-only)
@@ -3252,7 +3181,7 @@
// Verifies that BufferSubData calls don't trigger state updates for non-translated formats.
TEST_P(VulkanPerformanceCounterTest, BufferSubDataShouldNotTriggerSyncState)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
glUseProgram(testProgram);
@@ -3294,7 +3223,7 @@
// Verifies that rendering to backbuffer discards depth/stencil.
TEST_P(VulkanPerformanceCounterTest, SwapShouldInvalidateDepthStencil)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+0), stencil(Clears+1, Load+0, Stores+0)
@@ -3323,7 +3252,7 @@
// Verifies that rendering to MSAA backbuffer discards depth/stencil.
TEST_P(VulkanPerformanceCounterTest_MSAA, SwapShouldInvalidateDepthStencil)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
angle::VulkanPerfCounters expected;
// Expect rpCount+1, depth(Clears+1, Loads+0, Stores+0), stencil(Clears+1, Load+0, Stores+0)
@@ -3352,7 +3281,7 @@
// Tests that uniform updates eventually stop updating descriptor sets.
TEST_P(VulkanPerformanceCounterTest, UniformUpdatesHitDescriptorSetCache)
{
- ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kExtensionName));
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled(kPerfMonitorExtensionName));
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
glUseProgram(testProgram);
diff --git a/src/tests/perf_tests/ANGLEPerfTest.cpp b/src/tests/perf_tests/ANGLEPerfTest.cpp
index 7a4859b..30df5d8 100644
--- a/src/tests/perf_tests/ANGLEPerfTest.cpp
+++ b/src/tests/perf_tests/ANGLEPerfTest.cpp
@@ -13,6 +13,7 @@
#include "common/debug.h"
#include "common/mathutil.h"
#include "common/platform.h"
+#include "common/string_utils.h"
#include "common/system_utils.h"
#include "common/utilities.h"
#include "test_utils/runner/TestSuite.h"
@@ -467,6 +468,43 @@
mReporter->AddResult(".total_steps", static_cast<size_t>(mTotalNumStepsPerformed));
}
+ for (const auto &iter : mPerfCounterInfo)
+ {
+ const std::string &counterName = iter.second.name;
+ std::vector<GLuint> samples = iter.second.samples;
+
+ size_t midpoint = samples.size() >> 1;
+ std::nth_element(samples.begin(), samples.begin() + midpoint, samples.end());
+
+ {
+ std::stringstream medianStr;
+ medianStr << "." << counterName << "_median";
+ std::string medianName = medianStr.str();
+
+ mReporter->AddResult(medianName, static_cast<size_t>(samples[midpoint]));
+ }
+
+ {
+ std::string measurement = mName + mBackend + "." + counterName + "_median";
+ TestSuite::GetInstance()->addHistogramSample(measurement, mStory, samples[midpoint],
+ "count");
+ }
+
+ const auto &maxIt = std::max_element(samples.begin(), samples.end());
+
+ {
+ std::stringstream maxStr;
+ maxStr << "." << counterName << "_max";
+ std::string maxName = maxStr.str();
+ mReporter->AddResult(maxName, static_cast<size_t>(*maxIt));
+ }
+
+ {
+ std::string measurement = mName + mBackend + "." + counterName + "_max";
+ TestSuite::GetInstance()->addHistogramSample(measurement, mStory, *maxIt, "count");
+ }
+ }
+
return retValue;
}
@@ -835,6 +873,8 @@
// between calibration measurements.
calibrateStepsToRun(RunLoopPolicy::FinishEveryStep);
}
+
+ initPerfCounters();
}
void ANGLERenderTest::TearDown()
@@ -865,6 +905,73 @@
ANGLEPerfTest::TearDown();
}
+void ANGLERenderTest::initPerfCounters()
+{
+ if (!gPerfCounters)
+ {
+ return;
+ }
+
+ if (!IsGLExtensionEnabled(kPerfMonitorExtensionName))
+ {
+ fprintf(stderr, "Cannot report perf metrics because %s is not available.\n",
+ kPerfMonitorExtensionName);
+ return;
+ }
+
+ CounterNameToIndexMap indexMap = BuildCounterNameToIndexMap();
+
+ std::vector<std::string> counters =
+ angle::SplitString(gPerfCounters, ":", angle::WhitespaceHandling::TRIM_WHITESPACE,
+ angle::SplitResult::SPLIT_WANT_NONEMPTY);
+ for (const std::string &counter : counters)
+ {
+ auto iter = indexMap.find(counter);
+ if (iter == indexMap.end())
+ {
+ fprintf(stderr, "Counter '%s' not in list of available perf counters.\n",
+ counter.c_str());
+ }
+ else
+ {
+ {
+ std::stringstream medianStr;
+ medianStr << '.' << counter << "_median";
+ std::string medianName = medianStr.str();
+ mReporter->RegisterImportantMetric(medianName, "count");
+ }
+
+ {
+ std::stringstream maxStr;
+ maxStr << '.' << counter << "_max";
+ std::string maxName = maxStr.str();
+ mReporter->RegisterImportantMetric(maxName, "count");
+ }
+
+ GLuint index = indexMap[counter];
+ mPerfCounterInfo[index] = {counter, {}};
+ }
+ }
+}
+
+void ANGLERenderTest::updatePerfCounters()
+{
+ if (mPerfCounterInfo.empty())
+ {
+ return;
+ }
+
+ std::vector<PerfMonitorTriplet> perfData = GetPerfMonitorTriplets();
+ ASSERT(!perfData.empty());
+
+ for (auto &iter : mPerfCounterInfo)
+ {
+ uint32_t counter = iter.first;
+ std::vector<GLuint> &samples = iter.second.samples;
+ samples.push_back(perfData[counter].value);
+ }
+}
+
void ANGLERenderTest::beginInternalTraceEvent(const char *name)
{
if (gEnableTrace)
@@ -933,6 +1040,7 @@
// command queues.
if (mSwapEnabled)
{
+ updatePerfCounters();
mGLWindow->swap();
}
mOSWindow->messageLoop();
diff --git a/src/tests/perf_tests/ANGLEPerfTest.h b/src/tests/perf_tests/ANGLEPerfTest.h
index 3093dd4..a44beaf 100644
--- a/src/tests/perf_tests/ANGLEPerfTest.h
+++ b/src/tests/perf_tests/ANGLEPerfTest.h
@@ -122,6 +122,13 @@
int mIterationsPerStep;
bool mRunning;
std::vector<double> mTestTrialResults;
+
+ struct CounterInfo
+ {
+ std::string name;
+ std::vector<GLuint> samples;
+ };
+ angle::HashMap<GLuint, CounterInfo> mPerfCounterInfo;
};
enum class SurfaceType
@@ -190,6 +197,7 @@
void endGLTraceEvent(const char *name, double hostTimeSec);
void disableTestHarnessSwap() { mSwapEnabled = false; }
+ void updatePerfCounters();
bool mIsTimestampQueryAvailable;
@@ -204,6 +212,8 @@
bool areExtensionPrerequisitesFulfilled() const;
+ void initPerfCounters();
+
GLWindowBase *mGLWindow;
OSWindow *mOSWindow;
std::vector<const char *> mExtensionPrerequisites;
diff --git a/src/tests/perf_tests/ANGLEPerfTestArgs.cpp b/src/tests/perf_tests/ANGLEPerfTestArgs.cpp
index 313ab2c..af27464 100644
--- a/src/tests/perf_tests/ANGLEPerfTestArgs.cpp
+++ b/src/tests/perf_tests/ANGLEPerfTestArgs.cpp
@@ -29,6 +29,7 @@
bool gRetraceMode = false;
bool gMinimizeGPUWork = false;
bool gTraceTestValidation = false;
+const char *gPerfCounters = nullptr;
// Default to three warmup loops. There's no science to this. More than two loops was experimentally
// helpful on a Windows NVIDIA setup when testing with Vulkan and native trace tests.
@@ -171,5 +172,10 @@
gTestTrials = 1;
gMaxTrialTimeSeconds = 600.0;
}
+ else if (strcmp("--perf-counters", argv[argIndex]) == 0 && argIndex < *argc - 1)
+ {
+ gPerfCounters = argv[argIndex + 1];
+ argIndex++;
+ }
}
}
diff --git a/src/tests/perf_tests/ANGLEPerfTestArgs.h b/src/tests/perf_tests/ANGLEPerfTestArgs.h
index 91d8c51..3c71736 100644
--- a/src/tests/perf_tests/ANGLEPerfTestArgs.h
+++ b/src/tests/perf_tests/ANGLEPerfTestArgs.h
@@ -31,6 +31,7 @@
extern bool gRetraceMode;
extern bool gMinimizeGPUWork;
extern bool gTraceTestValidation;
+extern const char *gPerfCounters;
inline bool OneFrame()
{
diff --git a/src/tests/perf_tests/README.md b/src/tests/perf_tests/README.md
index 77e8666..f0d1ba9 100644
--- a/src/tests/perf_tests/README.md
+++ b/src/tests/perf_tests/README.md
@@ -42,6 +42,7 @@
* `--enable-all-trace-tests`: Offscreen and vsync-limited trace tests are disabled by default to reduce test time.
* `--minimize-gpu-work`: Modify API calls so that GPU work is reduced to minimum.
* `--validation`: Enable serialization validation in the trace tests. Normally used with SwiftShader and retracing.
+* `--perf-counters`: Additional performance counters to include in the result output. Separate multiple entries with colons: ':'.
For example, for an endless run with no warmup, run:
diff --git a/src/tests/perf_tests/TracePerfTest.cpp b/src/tests/perf_tests/TracePerfTest.cpp
index 7be1a7a..b76422c 100644
--- a/src/tests/perf_tests/TracePerfTest.cpp
+++ b/src/tests/perf_tests/TracePerfTest.cpp
@@ -1418,6 +1418,8 @@
mTraceLibrary->replayFrame(mCurrentFrame);
stopGpuTimer();
+ updatePerfCounters();
+
if (mParams.surfaceType == SurfaceType::Offscreen)
{
if (gMinimizeGPUWork)
diff --git a/src/tests/run_perf_tests.py b/src/tests/run_perf_tests.py
index 9d31507..693e4c8 100755
--- a/src/tests/run_perf_tests.py
+++ b/src/tests/run_perf_tests.py
@@ -303,6 +303,8 @@
default=DEFAULT_CALIBRATION_TIME)
parser.add_argument(
'--show-test-stdout', help='Prints all test stdout during execution.', action='store_true')
+ parser.add_argument(
+ '--perf-counters', help='Colon-separated list of extra perf counter metrics.')
args, extra_flags = parser.parse_known_args()
@@ -407,10 +409,15 @@
'--trials',
str(args.trials_per_sample),
]
+
if args.smoke_test_mode:
cmd_run += ['--no-warmup']
else:
cmd_run += ['--warmup-loops', str(args.warmup_loops)]
+
+ if args.perf_counters:
+ cmd_run += ['--perf-counters', args.perf_counters]
+
with common.temporary_file() as histogram_file_path:
cmd_run += ['--isolated-script-test-perf-output=%s' % histogram_file_path]
exit_code, output = _run_and_get_output(args, cmd_run, env)
diff --git a/src/tests/test_utils/runner/HistogramWriter.cpp b/src/tests/test_utils/runner/HistogramWriter.cpp
index 14074b4..6665a01 100644
--- a/src/tests/test_utils/runner/HistogramWriter.cpp
+++ b/src/tests/test_utils/runner/HistogramWriter.cpp
@@ -34,11 +34,59 @@
{
namespace
{
-std::string GetUnitAndDirection(proto::UnitAndDirection unit)
+std::string UnitAndDirectionToString(proto::UnitAndDirection unit)
{
- ASSERT(unit.improvement_direction() == proto::SMALLER_IS_BETTER);
- ASSERT(unit.unit() == proto::MS_BEST_FIT_FORMAT);
- return "msBestFitFormat_smallerIsBetter";
+ std::stringstream strstr;
+
+ switch (unit.unit())
+ {
+ case proto::MS_BEST_FIT_FORMAT:
+ strstr << "msBestFitFormat";
+ break;
+ case proto::COUNT:
+ strstr << "count";
+ break;
+ default:
+ UNREACHABLE();
+ strstr << "error";
+ break;
+ }
+
+ switch (unit.improvement_direction())
+ {
+ case proto::NOT_SPECIFIED:
+ break;
+ case proto::SMALLER_IS_BETTER:
+ strstr << "_smallerIsBetter";
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ return strstr.str();
+}
+
+proto::UnitAndDirection StringToUnitAndDirection(const std::string &str)
+{
+ proto::UnitAndDirection unitAndDirection;
+
+ if (str == "count")
+ {
+ unitAndDirection.set_improvement_direction(proto::NOT_SPECIFIED);
+ unitAndDirection.set_unit(proto::COUNT);
+ }
+ else if (str == "msBestFitFormat_smallerIsBetter")
+ {
+ unitAndDirection.set_improvement_direction(proto::SMALLER_IS_BETTER);
+ unitAndDirection.set_unit(proto::MS_BEST_FIT_FORMAT);
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+
+ return unitAndDirection;
}
} // namespace
@@ -54,9 +102,7 @@
std::string measurementAndStory = measurement + story;
if (mHistograms.count(measurementAndStory) == 0)
{
- proto::UnitAndDirection unitAndDirection;
- unitAndDirection.set_improvement_direction(proto::SMALLER_IS_BETTER);
- unitAndDirection.set_unit(proto::MS_BEST_FIT_FORMAT);
+ proto::UnitAndDirection unitAndDirection = StringToUnitAndDirection(units);
std::unique_ptr<catapult::HistogramBuilder> builder =
std::make_unique<catapult::HistogramBuilder>(measurement, unitAndDirection);
@@ -102,7 +148,7 @@
js::Value description(histogram.description(), allocator);
obj.AddMember("description", description, allocator);
- js::Value unitAndDirection(GetUnitAndDirection(histogram.unit()), allocator);
+ js::Value unitAndDirection(UnitAndDirectionToString(histogram.unit()), allocator);
obj.AddMember("unit", unitAndDirection, allocator);
if (histogram.has_diagnostics())
diff --git a/util/shader_utils.cpp b/util/shader_utils.cpp
index afc41d1..4473a13 100644
--- a/util/shader_utils.cpp
+++ b/util/shader_utils.cpp
@@ -135,6 +135,28 @@
callbackChain(source, type, id, severity, length, message, gCallbackChainUserParam);
}
}
+
+void GetPerfCounterValue(const CounterNameToIndexMap &counterIndexMap,
+ std::vector<angle::PerfMonitorTriplet> &triplets,
+ const char *name,
+ GLuint *counterOut)
+{
+ auto iter = counterIndexMap.find(name);
+ ASSERT(iter != counterIndexMap.end());
+ GLuint counterIndex = iter->second;
+
+ for (const angle::PerfMonitorTriplet &triplet : triplets)
+ {
+ ASSERT(triplet.group == 0);
+ if (triplet.counter == counterIndex)
+ {
+ *counterOut = triplet.value;
+ return;
+ }
+ }
+
+ UNREACHABLE();
+}
} // namespace
GLuint CompileShader(GLenum type, const char *source)
@@ -372,6 +394,98 @@
glDebugMessageCallbackKHR(DebugMessageCallback, reinterpret_cast<const void *>(callbackChain));
}
+CounterNameToIndexMap BuildCounterNameToIndexMap()
+{
+ GLint numCounters = 0;
+ glGetPerfMonitorCountersAMD(0, &numCounters, nullptr, 0, nullptr);
+ if (glGetError() != GL_NO_ERROR)
+ {
+ return {};
+ }
+
+ std::vector<GLuint> counterIndexes(numCounters, 0);
+ glGetPerfMonitorCountersAMD(0, nullptr, nullptr, numCounters, counterIndexes.data());
+ if (glGetError() != GL_NO_ERROR)
+ {
+ return {};
+ }
+
+ CounterNameToIndexMap indexMap;
+
+ for (GLuint counterIndex : counterIndexes)
+ {
+ static constexpr size_t kBufSize = 1000;
+ char buffer[kBufSize] = {};
+ glGetPerfMonitorCounterStringAMD(0, counterIndex, kBufSize, nullptr, buffer);
+ if (glGetError() != GL_NO_ERROR)
+ {
+ return {};
+ }
+
+ indexMap[buffer] = counterIndex;
+ }
+
+ return indexMap;
+}
+
+std::vector<angle::PerfMonitorTriplet> GetPerfMonitorTriplets()
+{
+ GLuint resultSize = 0;
+ glGetPerfMonitorCounterDataAMD(0, GL_PERFMON_RESULT_SIZE_AMD, sizeof(GLuint), &resultSize,
+ nullptr);
+ if (glGetError() != GL_NO_ERROR || resultSize == 0)
+ {
+ return {};
+ }
+
+ std::vector<angle::PerfMonitorTriplet> perfResults(resultSize /
+ sizeof(angle::PerfMonitorTriplet));
+ glGetPerfMonitorCounterDataAMD(
+ 0, GL_PERFMON_RESULT_AMD, static_cast<GLsizei>(perfResults.size() * sizeof(perfResults[0])),
+ &perfResults.data()->group, nullptr);
+
+ if (glGetError() != GL_NO_ERROR)
+ {
+ return {};
+ }
+
+ return perfResults;
+}
+
+angle::VulkanPerfCounters GetPerfCounters(const CounterNameToIndexMap &indexMap)
+{
+ std::vector<angle::PerfMonitorTriplet> perfResults = GetPerfMonitorTriplets();
+
+ angle::VulkanPerfCounters counters;
+
+#define ANGLE_UNPACK_PERF_COUNTER(COUNTER) \
+ GetPerfCounterValue(indexMap, perfResults, #COUNTER, &counters.COUNTER);
+
+ ANGLE_VK_PERF_COUNTERS_X(ANGLE_UNPACK_PERF_COUNTER)
+
+#undef ANGLE_UNPACK_PERF_COUNTER
+
+ return counters;
+}
+
+CounterNameToIndexMap BuildCounterNameToValueMap()
+{
+ CounterNameToIndexMap indexMap = BuildCounterNameToIndexMap();
+ std::vector<angle::PerfMonitorTriplet> perfResults = GetPerfMonitorTriplets();
+
+ CounterNameToValueMap valueMap;
+
+ for (const auto &iter : indexMap)
+ {
+ const std::string &name = iter.first;
+ GLuint index = iter.second;
+
+ valueMap[name] = perfResults[index].value;
+ }
+
+ return valueMap;
+}
+
namespace angle
{
diff --git a/util/shader_utils.h b/util/shader_utils.h
index e2efcc7..d490b17 100644
--- a/util/shader_utils.h
+++ b/util/shader_utils.h
@@ -8,9 +8,11 @@
#define SAMPLE_UTIL_SHADER_UTILS_H
#include <functional>
+#include <map>
#include <string>
#include <vector>
+#include "common/angleutils.h"
#include "util/util_export.h"
#include "util/util_gl.h"
@@ -51,6 +53,14 @@
ANGLE_UTIL_EXPORT void EnableDebugCallback(GLDEBUGPROC callbackChain, const void *userParam);
+using CounterNameToIndexMap = std::map<std::string, GLuint>;
+using CounterNameToValueMap = std::map<std::string, GLuint>;
+
+ANGLE_UTIL_EXPORT CounterNameToIndexMap BuildCounterNameToIndexMap();
+ANGLE_UTIL_EXPORT angle::VulkanPerfCounters GetPerfCounters(const CounterNameToIndexMap &indexMap);
+ANGLE_UTIL_EXPORT CounterNameToValueMap BuildCounterNameToValueMap();
+ANGLE_UTIL_EXPORT std::vector<angle::PerfMonitorTriplet> GetPerfMonitorTriplets();
+
namespace angle
{