Commit e4857c7d by Jamie Madill Committed by Commit Bot

Buffer11: Use adaptive threshold for releasing system memory.

The hard-coded threshold of five uses before a release was regressing the Oort online benchmark, which seems to use an index buffer many times, then change to a different range of indices, which would need to check the system memory for index range validation. Also add a performance regression test, and an update to the perf runner script which checks for the most recent binary among the search directories. BUG=594066 Change-Id: Id09cc32fd00bff1c72cbe9b6fb7c210fd047a551 Reviewed-on: https://chromium-review.googlesource.com/339271Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent b97a3e77
......@@ -26,6 +26,9 @@ perftests_paths = [
]
metric = 'score'
# TODO(jmadill): Linux binaries
binary_name = 'angle_perftests.exe'
scores = []
# Danke to http://stackoverflow.com/a/27758326
......@@ -63,13 +66,19 @@ def truncated_mean(data, n):
def truncated_stddev(data, n):
return pstdev(truncated_list(data, n))
perftests_path = ""
# Find most recent binary
newest_binary = None
newest_mtime = None
# TODO(jmadill): Linux binaries
for path in perftests_paths:
perftests_path = os.path.join(base_path, path, 'angle_perftests.exe')
if os.path.exists(perftests_path):
break
binary_path = os.path.join(base_path, path, binary_name)
binary_mtime = os.path.getmtime(binary_path)
if os.path.exists(binary_path):
if (newest_binary is None) or (binary_mtime > newest_mtime):
newest_binary = binary_path
newest_mtime = binary_mtime
perftests_path = newest_binary
if not os.path.exists(perftests_path):
print("Cannot find angle_perftests.exe!")
......
......@@ -270,7 +270,8 @@ Buffer11::Buffer11(Renderer11 *renderer)
mBufferStorages(BUFFER_USAGE_COUNT, nullptr),
mConstantBufferStorageAdditionalSize(0),
mMaxConstantBufferLruCount(0),
mReadUsageCount(0)
mReadUsageCount(0),
mSystemMemoryDeallocThreshold(0)
{
}
......@@ -491,21 +492,40 @@ gl::Error Buffer11::markTransformFeedbackUsage()
return gl::NoError();
}
void Buffer11::updateSystemMemoryDeallocThreshold()
{
// The following strategy was tuned on the Oort online benchmark (http://oortonline.gl/)
// as well as a custom microbenchmark (IndexConversionPerfTest.Run/index_range_d3d11)
// First readback: 8 unmodified uses before we free system memory.
// After that, double the threshold each time until we reach the max.
if (mSystemMemoryDeallocThreshold == 0)
{
mSystemMemoryDeallocThreshold = 8;
}
else if (IsUnsignedMultiplicationSafe(mSystemMemoryDeallocThreshold, 2u))
{
mSystemMemoryDeallocThreshold *= 2u;
}
else
{
mSystemMemoryDeallocThreshold = std::numeric_limits<unsigned int>::max();
}
}
gl::Error Buffer11::markBufferUsage()
{
mReadUsageCount++;
// Free the system memory storage if we decide it isn't being used very often.
const unsigned int usageLimit = 5;
BufferStorage *&sysMemUsage = mBufferStorages[BUFFER_USAGE_SYSTEM_MEMORY];
if (mReadUsageCount > usageLimit && sysMemUsage != nullptr)
BufferStorage *&sysMemStorage = mBufferStorages[BUFFER_USAGE_SYSTEM_MEMORY];
if (sysMemStorage != nullptr && mReadUsageCount > mSystemMemoryDeallocThreshold)
{
BufferStorage *latestStorage = nullptr;
ANGLE_TRY_RESULT(getLatestBufferStorage(), latestStorage);
if (latestStorage != sysMemUsage)
if (latestStorage != sysMemStorage)
{
SafeDelete(sysMemUsage);
SafeDelete(sysMemStorage);
}
}
......@@ -652,14 +672,17 @@ gl::ErrorOrResult<Buffer11::BufferStorage *> Buffer11::getBufferStorage(BufferUs
return newStorage;
}
Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage) const
Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage)
{
switch (usage)
{
case BUFFER_USAGE_PIXEL_PACK:
return new PackStorage(mRenderer);
case BUFFER_USAGE_SYSTEM_MEMORY:
{
updateSystemMemoryDeallocThreshold();
return new SystemMemoryStorage(mRenderer);
}
case BUFFER_USAGE_EMULATED_INDEXED_VERTEX:
return new EmulatedIndexedStorage(mRenderer);
case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
......
......@@ -129,7 +129,8 @@ class Buffer11 : public BufferD3D
gl::ErrorOrResult<BufferStorage *> getConstantBufferRangeStorage(GLintptr offset,
GLsizeiptr size);
BufferStorage *allocateStorage(BufferUsage usage) const;
BufferStorage *allocateStorage(BufferUsage usage);
void updateSystemMemoryDeallocThreshold();
Renderer11 *mRenderer;
size_t mSize;
......@@ -150,6 +151,7 @@ class Buffer11 : public BufferD3D
std::map<DXGI_FORMAT, BufferSRVPair> mBufferResourceViews;
unsigned int mReadUsageCount;
unsigned int mSystemMemoryDeallocThreshold;
NotificationSet mStaticBufferDirtyCallbacks;
NotificationSet mDirectBufferDirtyCallbacks;
......
......@@ -55,7 +55,7 @@ class ANGLEPerfTest : public testing::Test, angle::NonCopyable
// Call if the test step was aborted and the test should stop running.
void abortTest() { mRunning = false; }
int getNumStepsPerformed() const { return mNumStepsPerformed; }
unsigned int getNumStepsPerformed() const { return mNumStepsPerformed; }
std::string mName;
std::string mSuffix;
......@@ -63,7 +63,7 @@ class ANGLEPerfTest : public testing::Test, angle::NonCopyable
double mRunTimeSeconds;
private:
int mNumStepsPerformed;
unsigned int mNumStepsPerformed;
bool mRunning;
};
......
......@@ -23,6 +23,11 @@ struct IndexConversionPerfParams final : public RenderTestParams
{
std::stringstream strstr;
if (indexRangeOffset > 0)
{
strstr << "_index_range";
}
strstr << RenderTestParams::suffix();
return strstr.str();
......@@ -30,15 +35,15 @@ struct IndexConversionPerfParams final : public RenderTestParams
unsigned int iterations;
unsigned int numIndexTris;
// A second test, which covers using index ranges with an offset.
unsigned int indexRangeOffset;
};
// Provide a custom gtest parameter name function for IndexConversionPerfParams
// that includes the number of iterations and triangles in the test parameter name.
// This also fixes the resolution of the overloaded operator<< on MSVC.
// Provide a custom gtest parameter name function for IndexConversionPerfParams.
std::ostream &operator<<(std::ostream &stream, const IndexConversionPerfParams &param)
{
const PlatformParameters &platform = param;
stream << platform << "_" << param.iterations << "_" << param.numIndexTris;
stream << param.suffix().substr(1);
return stream;
}
......@@ -52,9 +57,11 @@ class IndexConversionPerfTest : public ANGLERenderTest,
void destroyBenchmark() override;
void drawBenchmark() override;
private:
void updateBufferData();
void drawConversion();
void drawIndexRange();
private:
GLuint mProgram;
GLuint mVertexBuffer;
GLuint mIndexBuffer;
......@@ -129,7 +136,16 @@ void IndexConversionPerfTest::initializeBenchmark()
// Initialize the index buffer
for (unsigned int triIndex = 0; triIndex < params.numIndexTris; ++triIndex)
{
mIndexData.push_back(std::numeric_limits<GLushort>::max());
// Handle two different types of tests, one with index conversion triggered by a -1 index.
if (params.indexRangeOffset == 0)
{
mIndexData.push_back(std::numeric_limits<GLushort>::max());
}
else
{
mIndexData.push_back(0);
}
mIndexData.push_back(1);
mIndexData.push_back(2);
}
......@@ -164,8 +180,20 @@ void IndexConversionPerfTest::destroyBenchmark()
void IndexConversionPerfTest::drawBenchmark()
{
glClear(GL_COLOR_BUFFER_BIT);
const auto &params = GetParam();
if (params.indexRangeOffset == 0)
{
drawConversion();
}
else
{
drawIndexRange();
}
}
void IndexConversionPerfTest::drawConversion()
{
const auto &params = GetParam();
// Trigger an update to ensure we convert once a frame
......@@ -182,6 +210,27 @@ void IndexConversionPerfTest::drawBenchmark()
ASSERT_GL_NO_ERROR();
}
void IndexConversionPerfTest::drawIndexRange()
{
const auto &params = GetParam();
unsigned int indexCount = 3;
size_t offset = static_cast<size_t>(indexCount * getNumStepsPerformed());
offset %= (params.numIndexTris * 3);
// This test increments an offset each step. Drawing repeatedly may cause the system memory
// to release. Then, using a fresh offset will require index range validation, which pages
// it back in. The performance should be good even if the data is was used quite a bit.
for (unsigned int it = 0; it < params.iterations; it++)
{
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(indexCount), GL_UNSIGNED_SHORT,
reinterpret_cast<GLvoid *>(offset));
}
ASSERT_GL_NO_ERROR();
}
IndexConversionPerfParams IndexConversionPerfD3D11Params()
{
IndexConversionPerfParams params;
......@@ -192,6 +241,21 @@ IndexConversionPerfParams IndexConversionPerfD3D11Params()
params.windowHeight = 256;
params.iterations = 225;
params.numIndexTris = 3000;
params.indexRangeOffset = 0;
return params;
}
IndexConversionPerfParams IndexRangeOffsetPerfD3D11Params()
{
IndexConversionPerfParams params;
params.eglParameters = egl_platform::D3D11_NULL();
params.majorVersion = 2;
params.minorVersion = 0;
params.windowWidth = 256;
params.windowHeight = 256;
params.iterations = 16;
params.numIndexTris = 50000;
params.indexRangeOffset = 64;
return params;
}
......@@ -201,6 +265,7 @@ TEST_P(IndexConversionPerfTest, Run)
}
ANGLE_INSTANTIATE_TEST(IndexConversionPerfTest,
IndexConversionPerfD3D11Params());
IndexConversionPerfD3D11Params(),
IndexRangeOffsetPerfD3D11Params());
} // namespace
} // namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment