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>
This commit is contained in:
Jamie Madill
2022-03-09 13:56:36 -05:00
committed by Angle LUCI CQ
parent 24ad581e7e
commit 3739a195c2
12 changed files with 363 additions and 127 deletions

View File

@@ -90,6 +90,8 @@ struct SaveFileHelper
};
// AMD_performance_monitor helpers.
constexpr char kPerfMonitorExtensionName[] = "GL_AMD_performance_monitor";
struct PerfMonitorCounter
{
PerfMonitorCounter();

View File

@@ -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 @@ class VulkanPerformanceCounterTest : public ANGLETest
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 @@ class VulkanPerformanceCounterTest_MSAA : public VulkanPerformanceCounterTest
// 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 @@ TEST_P(VulkanPerformanceCounterTest, NewTextureDoesNotBreakRenderPass)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, SampleFromRGBTextureDoesNotBreakRenderPass)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, RenderToRGBTextureDoesNotBreakRenderPass)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, ChangingMaxLevelHitsDescriptorCache)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, IndependentBufferCopiesShareSingleBarrier)
// 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 @@ TEST_P(VulkanPerformanceCounterTest_ES31, MultisampleResolveWithBlit)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthStencilFeedbackLoopUsesSingleR
// - 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 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDisableDraw)
// - 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 @@ TEST_P(VulkanPerformanceCounterTest, DisableInvalidateDraw)
// - 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 @@ TEST_P(VulkanPerformanceCounterTest, DisableDrawInvalidateEnable)
// - 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 @@ TEST_P(VulkanPerformanceCounterTest, Invalidate)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateSub)
// - 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 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDraw)
// - 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 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisable)
// - 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 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDisableDrawEnable)
// - 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 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDisableDrawEnableDraw)
// - 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 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisableEnable)
// - 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 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisableEnableInvalidate)
// - 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 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDrawDisableEnableInvalidateDraw)
// - 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 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDisableEnableDraw)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateAndClear)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateAndMaskedClear)
// - 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 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDetachModifyTexAttachDrawWithBlen
// - 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 @@ TEST_P(VulkanPerformanceCounterTest, InvalidateDrawAndDeleteRenderbuffer)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, SwapShouldInvalidateDepthAfterClear)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, MaskedColorClearDoesNotBreakRenderPass)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, MaskedClearDoesNotBreakRenderPass)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, ClearThenScissoredDraw)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, ScissoredClearDoesNotBreakRenderPass)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, DrawbufferChangeWithAllColorMaskDisabled)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, InRenderpassFlushShouldNotBreakRenderpass)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, DepthStencilTextureClearAndLoad)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilRenderbufferShou
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 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureInvalidate)
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 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureUninitializedAndUnusedDepthS
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 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureUninitializedAndUnusedDepthS
// 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 @@ TEST_P(VulkanPerformanceCounterTest, ReadOnlyDepthBufferLayout)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, RenderPassAfterRenderPassWithoutDepthStenci
// 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 @@ TEST_P(VulkanPerformanceCounterTest, ClearAfterClearDoesNotBreakRenderPass)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, ScissorDoesNotBreakRenderPass)
// 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 @@ void main()
// 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 @@ void main()
// 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 @@ TEST_P(VulkanPerformanceCounterTest, BufferSubDataShouldNotTriggerSyncState)
// 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 @@ TEST_P(VulkanPerformanceCounterTest, SwapShouldInvalidateDepthStencil)
// 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 @@ TEST_P(VulkanPerformanceCounterTest_MSAA, SwapShouldInvalidateDepthStencil)
// 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);

View File

@@ -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 @@ double ANGLEPerfTest::printResults()
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 @@ void ANGLERenderTest::SetUp()
// between calibration measurements.
calibrateStepsToRun(RunLoopPolicy::FinishEveryStep);
}
initPerfCounters();
}
void ANGLERenderTest::TearDown()
@@ -865,6 +905,73 @@ void ANGLERenderTest::TearDown()
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 @@ void ANGLERenderTest::step()
// command queues.
if (mSwapEnabled)
{
updatePerfCounters();
mGLWindow->swap();
}
mOSWindow->messageLoop();

View File

@@ -122,6 +122,13 @@ class ANGLEPerfTest : public testing::Test, angle::NonCopyable
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 @@ class ANGLERenderTest : public ANGLEPerfTest
void endGLTraceEvent(const char *name, double hostTimeSec);
void disableTestHarnessSwap() { mSwapEnabled = false; }
void updatePerfCounters();
bool mIsTimestampQueryAvailable;
@@ -204,6 +212,8 @@ class ANGLERenderTest : public ANGLEPerfTest
bool areExtensionPrerequisitesFulfilled() const;
void initPerfCounters();
GLWindowBase *mGLWindow;
OSWindow *mOSWindow;
std::vector<const char *> mExtensionPrerequisites;

View File

@@ -29,6 +29,7 @@ bool gEnableAllTraceTests = false;
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 @@ void ANGLEProcessPerfTestArgs(int *argc, char **argv)
gTestTrials = 1;
gMaxTrialTimeSeconds = 600.0;
}
else if (strcmp("--perf-counters", argv[argIndex]) == 0 && argIndex < *argc - 1)
{
gPerfCounters = argv[argIndex + 1];
argIndex++;
}
}
}

View File

@@ -31,6 +31,7 @@ extern bool gEnableAllTraceTests;
extern bool gRetraceMode;
extern bool gMinimizeGPUWork;
extern bool gTraceTestValidation;
extern const char *gPerfCounters;
inline bool OneFrame()
{

View File

@@ -42,6 +42,7 @@ Several command-line arguments control how the tests run:
* `--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:

View File

@@ -1418,6 +1418,8 @@ void TracePerfTest::drawBenchmark()
mTraceLibrary->replayFrame(mCurrentFrame);
stopGpuTimer();
updatePerfCounters();
if (mParams.surfaceType == SurfaceType::Offscreen)
{
if (gMinimizeGPUWork)

View File

@@ -303,6 +303,8 @@ def main():
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 @@ def main():
'--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)

View File

@@ -34,11 +34,59 @@ namespace angle
{
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 @@ void HistogramWriter::addSample(const std::string &measurement,
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 @@ void HistogramWriter::getAsJSON(js::Document *doc) const
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())

View File

@@ -135,6 +135,28 @@ void KHRONOS_APIENTRY DebugMessageCallback(GLenum source,
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 @@ void EnableDebugCallback(GLDEBUGPROC callbackChain, const void *userParam)
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
{

View File

@@ -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 GLuint LoadBinaryProgramES3(const std::vector<uint8_t> &binary
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
{