Skip to content

Commit

Permalink
Add basic begin/end support for perf counters
Browse files Browse the repository at this point in the history
The AMD_performance_monitor extension has explicit begin/end calls to
capture counters.  This was not implemented in ANGLE and the tests were
relying on ANGLE always capturing counters (incurring a small overhead).

This change does not complete the implementation of that extension, but
does add basic support for starting and stopping perf counter
measurements.  While inactive, most counters are not updated.

Bug: angleproject:42267038
Change-Id: I3ff6448b22ca247c217401cb2d76ef4142c9d759
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5639343
Commit-Queue: Shahbaz Youssefi <[email protected]>
Reviewed-by: Cody Northrop <[email protected]>
Reviewed-by: Amirali Abdolrashidi <[email protected]>
  • Loading branch information
ShabbyX authored and Angle LUCI CQ committed Jun 21, 2024
1 parent 29f9a8c commit 3f57290
Show file tree
Hide file tree
Showing 16 changed files with 128 additions and 16 deletions.
10 changes: 8 additions & 2 deletions src/libANGLE/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9674,11 +9674,17 @@ void Context::finishImmutable() const
ANGLE_CONTEXT_TRY(mImplementation->finish(this));
}

void Context::beginPerfMonitor(GLuint monitor) {}
void Context::beginPerfMonitor(GLuint monitor)
{
getMutablePrivateState()->setPerfMonitorActive(true);
}

void Context::deletePerfMonitors(GLsizei n, GLuint *monitors) {}

void Context::endPerfMonitor(GLuint monitor) {}
void Context::endPerfMonitor(GLuint monitor)
{
getMutablePrivateState()->setPerfMonitorActive(false);
}

void Context::genPerfMonitors(GLsizei n, GLuint *monitors)
{
Expand Down
1 change: 1 addition & 0 deletions src/libANGLE/ErrorStrings.h
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ MSG kOffsetOverflow = "Offset overflows texture dimensions.";
MSG kOtherQueryActive = "Other query is active.";
MSG kOutsideOfBounds = "Parameter outside of bounds.";
MSG kParamOverflow = "The provided parameters overflow with the provided buffer.";
MSG kPerfMonitorNotActive = "Perf monitor is not started.";
MSG kPixelDataNotNull = "Pixel data must be null.";
MSG kPixelDataNull = "Pixel data cannot be null.";
MSG kPixelPackBufferBoundForTransformFeedback = "It is undefined behavior to use a pixel pack buffer that is bound for transform feedback.";
Expand Down
1 change: 1 addition & 0 deletions src/libANGLE/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ PrivateState::PrivateState(const EGLenum clientType,
mShadingRatePreserveAspectRatio(false),
mShadingRate(ShadingRate::Undefined),
mFetchPerSample(false),
mIsPerfMonitorActive(false),
mBindGeneratesResource(bindGeneratesResourceCHROMIUM),
mClientArraysEnabled(clientArraysEnabled),
mRobustResourceInit(robustResourceInit),
Expand Down
7 changes: 7 additions & 0 deletions src/libANGLE/State.h
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,9 @@ class PrivateState : angle::NonCopyable
const state::DirtyObjects &getDirtyObjects() const { return mDirtyObjects; }
void clearDirtyObjects() { mDirtyObjects.reset(); }

void setPerfMonitorActive(bool active) { mIsPerfMonitorActive = active; }
bool isPerfMonitorActive() const { return mIsPerfMonitorActive; }

private:
bool hasConstantColor(GLenum sourceRGB, GLenum destRGB) const;
bool hasConstantAlpha(GLenum sourceRGB, GLenum destRGB) const;
Expand Down Expand Up @@ -725,6 +728,9 @@ class PrivateState : angle::NonCopyable
// GL_ARM_shader_framebuffer_fetch
bool mFetchPerSample;

// Whether perf monitoring is enabled through GL_AMD_performance_monitor.
bool mIsPerfMonitorActive;

const bool mBindGeneratesResource;
const bool mClientArraysEnabled;
const bool mRobustResourceInit;
Expand Down Expand Up @@ -1406,6 +1412,7 @@ class State : angle::NonCopyable
}
bool isLogicOpEnabled() const { return mPrivateState.isLogicOpEnabled(); }
LogicalOperation getLogicOp() const { return mPrivateState.getLogicOp(); }
bool isPerfMonitorActive() const { return mPrivateState.isPerfMonitorActive(); }
const Debug &getDebug() const { return mPrivateState.getDebug(); }
Debug &getDebug() { return mPrivateState.getDebug(); }
bool getEnableFeature(GLenum feature) const { return mPrivateState.getEnableFeature(feature); }
Expand Down
4 changes: 2 additions & 2 deletions src/libANGLE/capture/capture_gles_ext_params.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4175,7 +4175,7 @@ void CaptureDeletePerfMonitorsAMD_monitors(const State &glState,
GLuint *monitors,
angle::ParamCapture *paramCapture)
{
UNIMPLEMENTED();
CaptureArray(monitors, n, paramCapture);
}

void CaptureGenPerfMonitorsAMD_monitors(const State &glState,
Expand All @@ -4184,7 +4184,7 @@ void CaptureGenPerfMonitorsAMD_monitors(const State &glState,
GLuint *monitors,
angle::ParamCapture *paramCapture)
{
UNIMPLEMENTED();
CaptureArray(monitors, n, paramCapture);
}

void CaptureGetPerfMonitorCounterDataAMD_data(const State &glState,
Expand Down
5 changes: 5 additions & 0 deletions src/libANGLE/renderer/vulkan/ContextVk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3437,6 +3437,11 @@ angle::Result ContextVk::handleDirtyDescriptorSetsImpl(CommandBufferHelperT *com

void ContextVk::syncObjectPerfCounters(const angle::VulkanPerfCounters &commandQueuePerfCounters)
{
if (!mState.isPerfMonitorActive())
{
return;
}

mPerfCounters.descriptorSetCacheTotalSize = 0;
mPerfCounters.descriptorSetCacheKeySizeBytes = 0;
mPerfCounters.uniformsAndXfbDescriptorSetCacheHits = 0;
Expand Down
19 changes: 11 additions & 8 deletions src/libANGLE/validationESEXT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4188,8 +4188,7 @@ bool ValidateBeginPerfMonitorAMD(const Context *context,
return false;
}

UNIMPLEMENTED();
return false;
return true;
}

bool ValidateDeletePerfMonitorsAMD(const Context *context,
Expand All @@ -4203,8 +4202,8 @@ bool ValidateDeletePerfMonitorsAMD(const Context *context,
return false;
}

UNIMPLEMENTED();
return false;
// Note: ANGLE does not really create monitor objects or track ids.
return true;
}

bool ValidateEndPerfMonitorAMD(const Context *context, angle::EntryPoint entryPoint, GLuint monitor)
Expand All @@ -4215,8 +4214,13 @@ bool ValidateEndPerfMonitorAMD(const Context *context, angle::EntryPoint entryPo
return false;
}

UNIMPLEMENTED();
return false;
if (!context->getState().isPerfMonitorActive())
{
ANGLE_VALIDATION_ERROR(GL_INVALID_OPERATION, kPerfMonitorNotActive);
return false;
}

return true;
}

bool ValidateGenPerfMonitorsAMD(const Context *context,
Expand All @@ -4230,8 +4234,7 @@ bool ValidateGenPerfMonitorsAMD(const Context *context,
return false;
}

UNIMPLEMENTED();
return false;
return true;
}

bool ValidateGetPerfMonitorCounterDataAMD(const Context *context,
Expand Down
5 changes: 5 additions & 0 deletions src/tests/gl_tests/ImageTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4654,6 +4654,9 @@ TEST_P(ImageTestES3, AHBImportReleaseStress)

glFinish();

GLPerfMonitor monitor;
glBeginPerfMonitorAMD(monitor);

const uint64_t initialPendingSubmissionGarbageObjects =
getPerfCounters().pendingSubmissionGarbageObjects;

Expand All @@ -4680,6 +4683,8 @@ TEST_P(ImageTestES3, AHBImportReleaseStress)
destroyAndroidHardwareBuffer(ahb);
}

glEndPerfMonitorAMD(monitor);

EXPECT_LE(getPerfCounters().pendingSubmissionGarbageObjects,
initialPendingSubmissionGarbageObjects + 10);
}
Expand Down
12 changes: 12 additions & 0 deletions src/tests/gl_tests/TextureTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3579,6 +3579,9 @@ TEST_P(Texture2DMemoryTestES3, TextureDataInLoopUntilFlush)
// submissions.
ANGLE_SKIP_TEST_IF(getEGLWindow()->isFeatureEnabled(Feature::SupportsHostImageCopy));

GLPerfMonitor monitor;
glBeginPerfMonitorAMD(monitor);

uint64_t expectedSubmitCalls = getPerfCounters().commandQueueSubmitCallsTotal + 1;

// Set up program
Expand Down Expand Up @@ -3639,6 +3642,8 @@ void main()
break;
}
}
glEndPerfMonitorAMD(monitor);

EXPECT_EQ(getPerfCounters().commandQueueSubmitCallsTotal, expectedSubmitCalls);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
Expand All @@ -3651,6 +3656,10 @@ TEST_P(Texture2DMemoryTestES3, TextureDataInLoopManyTimes)
{
// Run this test for Vulkan only.
ANGLE_SKIP_TEST_IF(!IsVulkan());

GLPerfMonitor monitor;
glBeginPerfMonitorAMD(monitor);

uint64_t expectedSubmitCalls = getPerfCounters().commandQueueSubmitCallsTotal + 1;
uint64_t expectedDeviceMemoryFallbacks = getPerfCounters().deviceMemoryImageAllocationFallbacks;

Expand Down Expand Up @@ -3714,6 +3723,9 @@ void main()
break;
}
}

glEndPerfMonitorAMD(monitor);

EXPECT_EQ(getPerfCounters().commandQueueSubmitCallsTotal, expectedSubmitCalls);
EXPECT_EQ(getPerfCounters().deviceMemoryImageAllocationFallbacks,
expectedDeviceMemoryFallbacks);
Expand Down
5 changes: 5 additions & 0 deletions src/tests/gl_tests/UniformBufferTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3762,6 +3762,9 @@ class UniformBufferMemoryTest : public UniformBufferTest
// supposedly to issue flush if needed.
TEST_P(UniformBufferMemoryTest, BufferDataInLoopManyTimes)
{
GLPerfMonitor monitor;
glBeginPerfMonitorAMD(monitor);

// Run this test for Vulkan only.
ANGLE_SKIP_TEST_IF(!IsVulkan());
uint64_t expectedSubmitCalls = getPerfCounters().commandQueueSubmitCallsTotal + 1;
Expand Down Expand Up @@ -3801,6 +3804,8 @@ TEST_P(UniformBufferMemoryTest, BufferDataInLoopManyTimes)
break;
}
}
glEndPerfMonitorAMD(monitor);

EXPECT_EQ(getPerfCounters().commandQueueSubmitCallsTotal, expectedSubmitCalls);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
Expand Down
20 changes: 20 additions & 0 deletions src/tests/gl_tests/VulkanImageTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,9 @@ TEST_P(VulkanMemoryTest, AllocateVMAImageWhenDeviceOOM)
{
ANGLE_SKIP_TEST_IF(!getEGLWindow()->isFeatureEnabled(Feature::UseVmaForImageSuballocation));

GLPerfMonitor monitor;
glBeginPerfMonitorAMD(monitor);

VulkanHelper helper;
helper.initializeFromANGLE();
uint64_t expectedAllocationFallbacks =
Expand Down Expand Up @@ -596,6 +599,8 @@ TEST_P(VulkanMemoryTest, AllocateVMAImageWhenDeviceOOM)
EXPECT_EQ(getPerfCounters().deviceMemoryImageAllocationFallbacks,
expectedAllocationFallbacksAfterLastTexture);

glEndPerfMonitorAMD(monitor);

GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
Expand All @@ -609,6 +614,9 @@ TEST_P(VulkanMemoryTest, AllocateVMAImageAfterFreeing2DArrayGarbageWhenDeviceOOM
{
ANGLE_SKIP_TEST_IF(!getEGLWindow()->isFeatureEnabled(Feature::UseVmaForImageSuballocation));

GLPerfMonitor monitor;
glBeginPerfMonitorAMD(monitor);

VulkanHelper helper;
helper.initializeFromANGLE();
uint64_t expectedAllocationFallbacks =
Expand Down Expand Up @@ -689,6 +697,8 @@ TEST_P(VulkanMemoryTest, AllocateVMAImageAfterFreeing2DArrayGarbageWhenDeviceOOM
GL_UNSIGNED_BYTE, lastTextureColor.data());
EXPECT_EQ(getPerfCounters().deviceMemoryImageAllocationFallbacks, expectedAllocationFallbacks);

glEndPerfMonitorAMD(monitor);

GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, lastTexture, 0);
Expand All @@ -702,6 +712,9 @@ TEST_P(VulkanMemoryTest, AllocateVMAImageAfterFreeingFinished2DGarbageWhenDevice
{
ANGLE_SKIP_TEST_IF(!getEGLWindow()->isFeatureEnabled(Feature::UseVmaForImageSuballocation));

GLPerfMonitor monitor;
glBeginPerfMonitorAMD(monitor);

VulkanHelper helper;
helper.initializeFromANGLE();
uint64_t expectedAllocationFallbacks =
Expand Down Expand Up @@ -797,6 +810,8 @@ TEST_P(VulkanMemoryTest, AllocateVMAImageAfterFreeingFinished2DGarbageWhenDevice
EXPECT_EQ(getPerfCounters().deviceMemoryImageAllocationFallbacks, expectedAllocationFallbacks);
EXPECT_EQ(getPerfCounters().commandQueueSubmitCallsTotal, expectedSubmitCalls);

glEndPerfMonitorAMD(monitor);

GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, lastTexture, 0);
Expand All @@ -810,6 +825,9 @@ TEST_P(VulkanMemoryTest, AllocateBufferAfterFreeing2DGarbageWhenDeviceOOM)
{
ANGLE_SKIP_TEST_IF(!getEGLWindow()->isFeatureEnabled(Feature::UseVmaForImageSuballocation));

GLPerfMonitor monitor;
glBeginPerfMonitorAMD(monitor);

VulkanHelper helper;
helper.initializeFromANGLE();
uint64_t expectedAllocationFallbacks =
Expand Down Expand Up @@ -867,6 +885,8 @@ TEST_P(VulkanMemoryTest, AllocateBufferAfterFreeing2DGarbageWhenDeviceOOM)
}
EXPECT_EQ(getPerfCounters().deviceMemoryImageAllocationFallbacks, expectedAllocationFallbacks);

glEndPerfMonitorAMD(monitor);

// Wait until GPU finishes execution.
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
Expand Down
13 changes: 13 additions & 0 deletions src/tests/gl_tests/VulkanPerformanceCounterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,18 @@ class VulkanPerformanceCounterTest : public ANGLETest<>

static constexpr GLsizei kOpsTestSize = 16;

void testSetUp() override
{
glGenPerfMonitorsAMD(1, &monitor);
glBeginPerfMonitorAMD(monitor);
}

void testTearDown() override
{
glEndPerfMonitorAMD(monitor);
glDeletePerfMonitorsAMD(1, &monitor);
}

void setupForColorOpsTest(GLFramebuffer *framebuffer, GLTexture *texture)
{
// Setup the framebuffer
Expand Down Expand Up @@ -416,6 +428,7 @@ class VulkanPerformanceCounterTest : public ANGLETest<>
!isFeatureEnabled(Feature::DisableDepthStencilResolveThroughAttachment);
}

GLuint monitor;
CounterNameToIndexMap mIndexMap;
};

Expand Down
29 changes: 27 additions & 2 deletions src/tests/perf_tests/ANGLEPerfTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,8 @@ ANGLEPerfTest::ANGLEPerfTest(const std::string &name,
mTrialNumStepsPerformed(0),
mTotalNumStepsPerformed(0),
mIterationsPerStep(iterationsPerStep),
mRunning(true)
mRunning(true),
mPerfMonitor(0)
{
if (mStory == "")
{
Expand Down Expand Up @@ -1043,6 +1044,12 @@ void ANGLERenderTest::TearDown()
{
ASSERT(mTimestampQueries.empty());

if (!mPerfCounterInfo.empty())
{
glDeletePerfMonitorsAMD(1, &mPerfMonitor);
mPerfMonitor = 0;
}

if (!mSkipTest)
{
destroyBenchmark();
Expand Down Expand Up @@ -1130,6 +1137,13 @@ void ANGLERenderTest::initPerfCounters()
fprintf(stderr, "'%s' does not match any available perf counters.\n", counter.c_str());
}
}

if (!mPerfCounterInfo.empty())
{
glGenPerfMonitorsAMD(1, &mPerfMonitor);
// Note: technically, glSelectPerfMonitorCountersAMD should be used to select the counters,
// but currently ANGLE always captures all counters.
}
}

void ANGLERenderTest::updatePerfCounters()
Expand Down Expand Up @@ -1295,7 +1309,13 @@ void ANGLERenderTest::computeGPUTime()
}
}

void ANGLERenderTest::startTest() {}
void ANGLERenderTest::startTest()
{
if (!mPerfCounterInfo.empty())
{
glBeginPerfMonitorAMD(mPerfMonitor);
}
}

void ANGLERenderTest::finishTest()
{
Expand All @@ -1304,6 +1324,11 @@ void ANGLERenderTest::finishTest()
{
FinishAndCheckForContextLoss();
}

if (!mPerfCounterInfo.empty())
{
glEndPerfMonitorAMD(mPerfMonitor);
}
}

bool ANGLERenderTest::popEvent(Event *event)
Expand Down
Loading

0 comments on commit 3f57290

Please sign in to comment.