1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program EGL Module
3 * ---------------------------------------
5 * Copyright 2014 The Android Open Source Project
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
21 * \brief Memory object allocation stress tests
22 *//*--------------------------------------------------------------------*/
24 #include "teglMemoryStressTests.hpp"
26 #include "tcuTestLog.hpp"
27 #include "tcuCommandLine.hpp"
29 #include "deRandom.hpp"
33 #include "gluDefs.hpp"
34 #include "glwFunctions.hpp"
35 #include "glwDefs.hpp"
36 #include "glwEnums.hpp"
38 #include "egluUtil.hpp"
40 #include "eglwLibrary.hpp"
41 #include "eglwEnums.hpp"
62 OBJECTTYPE_PBUFFER = (1<<0),
63 OBJECTTYPE_CONTEXT = (1<<1),
72 MemoryAllocator (EglTestContext& eglTestCtx, EGLDisplay display, EGLConfig config, int seed, ObjectType types, int minWidth, int minHeight, int maxWidth, int maxHeight, bool use);
73 ~MemoryAllocator (void);
75 bool allocateUntilFailure (void);
76 int getAllocationCount (void) const { return (int)(m_pbuffers.size() + m_contexts.size()); }
77 int getContextCount (void) const { return (int)m_contexts.size(); }
78 int getPBufferCount (void) const { return (int)m_pbuffers.size(); }
79 const string& getErrorString (void) const { return m_errorString; }
82 void allocatePBuffer (void);
83 void allocateContext (void);
85 EglTestContext& m_eglTestCtx;
101 vector<EGLSurface> m_pbuffers;
102 vector<EGLContext> m_contexts;
105 MemoryAllocator::MemoryAllocator (EglTestContext& eglTestCtx, EGLDisplay display, EGLConfig config, int seed, ObjectType types, int minWidth, int minHeight, int maxWidth, int maxHeight, bool use)
106 : m_eglTestCtx (eglTestCtx)
107 , m_display (display)
114 , m_minWidth (minWidth)
115 , m_minHeight (minHeight)
116 , m_maxWidth (maxWidth)
117 , m_maxHeight (maxHeight)
120 m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
123 MemoryAllocator::~MemoryAllocator (void)
125 const Library& egl = m_eglTestCtx.getLibrary();
127 for (vector<EGLSurface>::const_iterator iter = m_pbuffers.begin(); iter != m_pbuffers.end(); ++iter)
128 egl.destroySurface(m_display, *iter);
132 for (vector<EGLContext>::const_iterator iter = m_contexts.begin(); iter != m_contexts.end(); ++iter)
133 egl.destroyContext(m_display, *iter);
138 bool MemoryAllocator::allocateUntilFailure (void)
140 const deUint64 timeLimitUs = 10000000; // 10s
141 deUint64 beginTimeUs = deGetMicroseconds();
142 vector<ObjectType> types;
144 if ((m_types & OBJECTTYPE_CONTEXT) != 0)
145 types.push_back(OBJECTTYPE_CONTEXT);
147 if ((m_types & OBJECTTYPE_PBUFFER) != 0)
148 types.push_back(OBJECTTYPE_PBUFFER);
150 // If objects should be used. Create one of both at beginning to allow using them.
151 if (m_contexts.size() == 0 && m_pbuffers.size() == 0 && m_use)
159 ObjectType type = m_rnd.choose<ObjectType>(types.begin(), types.end());
163 case OBJECTTYPE_PBUFFER:
167 case OBJECTTYPE_CONTEXT:
175 if (deGetMicroseconds() - beginTimeUs > timeLimitUs)
182 void MemoryAllocator::allocatePBuffer (void)
184 // Reserve space for new allocations
187 m_pbuffers.reserve(m_pbuffers.size() + 1);
189 catch (const std::bad_alloc&)
191 m_errorString = "std::bad_alloc when allocating more space for testcase. Out of host memory.";
199 const Library& egl = m_eglTestCtx.getLibrary();
200 const EGLint width = m_rnd.getInt(m_minWidth, m_maxWidth);
201 const EGLint height = m_rnd.getInt(m_minHeight, m_maxHeight);
202 const EGLint attribList[] =
209 EGLSurface surface = egl.createPbufferSurface(m_display, m_config, attribList);
210 EGLU_CHECK_MSG(egl, "eglCreatePbufferSurface");
212 DE_ASSERT(surface != EGL_NO_SURFACE);
214 m_pbuffers.push_back(surface);
216 if (m_use && m_contexts.size() > 0)
218 EGLContext context = m_rnd.choose<EGLContext>(m_contexts.begin(), m_contexts.end());
219 const float red = m_rnd.getFloat();
220 const float green = m_rnd.getFloat();
221 const float blue = m_rnd.getFloat();
222 const float alpha = m_rnd.getFloat();
224 EGLU_CHECK_CALL(egl, makeCurrent(m_display, surface, surface, context));
226 m_gl.clearColor(red, green, blue, alpha);
227 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearColor()");
229 m_gl.clear(GL_COLOR_BUFFER_BIT);
230 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClear()");
232 EGLU_CHECK_CALL(egl, makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
235 catch (const eglu::Error& error)
237 if (error.getError() == EGL_BAD_ALLOC)
239 m_errorString = "eglCreatePbufferSurface returned EGL_BAD_ALLOC";
248 void MemoryAllocator::allocateContext (void)
250 // Reserve space for new allocations
253 m_contexts.reserve(m_contexts.size() + 1);
255 catch (const std::bad_alloc&)
257 m_errorString = "std::bad_alloc when allocating more space for testcase. Out of host memory.";
265 const Library& egl = m_eglTestCtx.getLibrary();
266 const EGLint attribList[] =
268 EGL_CONTEXT_CLIENT_VERSION, 2,
272 EGLU_CHECK_CALL(egl, bindAPI(EGL_OPENGL_ES_API));
273 EGLContext context = egl.createContext(m_display, m_config, EGL_NO_CONTEXT, attribList);
274 EGLU_CHECK_MSG(egl, "eglCreateContext");
276 DE_ASSERT(context != EGL_NO_CONTEXT);
278 m_contexts.push_back(context);
280 if (m_use && m_pbuffers.size() > 0)
282 EGLSurface surface = m_rnd.choose<EGLSurface>(m_pbuffers.begin(), m_pbuffers.end());
283 const float red = m_rnd.getFloat();
284 const float green = m_rnd.getFloat();
285 const float blue = m_rnd.getFloat();
286 const float alpha = m_rnd.getFloat();
288 EGLU_CHECK_CALL(egl, makeCurrent(m_display, surface, surface, context));
290 m_gl.clearColor(red, green, blue, alpha);
291 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearColor()");
293 m_gl.clear(GL_COLOR_BUFFER_BIT);
294 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClear()");
296 EGLU_CHECK_CALL(egl, makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
299 catch (const eglu::Error& error)
301 if (error.getError() == EGL_BAD_ALLOC)
303 m_errorString = "eglCreateContext returned EGL_BAD_ALLOC";
314 class MemoryStressCase : public TestCase
327 MemoryStressCase (EglTestContext& eglTestCtx, Spec spec, const char* name, const char* description);
330 IterateResult iterate (void);
334 vector<int> m_allocationCounts;
335 MemoryAllocator* m_allocator;
338 int m_iterationCount;
340 EGLDisplay m_display;
344 MemoryStressCase::MemoryStressCase (EglTestContext& eglTestCtx, Spec spec, const char* name, const char* description)
345 : TestCase (eglTestCtx, name, description)
349 , m_iterationCount (10)
350 , m_seed (deStringHash(name))
351 , m_display (EGL_NO_DISPLAY)
356 void MemoryStressCase::init (void)
358 const Library& egl = m_eglTestCtx.getLibrary();
359 EGLint configCount = 0;
360 const EGLint attribList[] =
362 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
363 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
367 if (!m_testCtx.getCommandLine().isOutOfMemoryTestEnabled())
369 m_testCtx.getLog() << TestLog::Message << "Tests that exhaust memory are disabled, use --deqp-test-oom=enable command line option to enable." << TestLog::EndMessage;
370 throw tcu::NotSupportedError("OOM tests disabled");
373 m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
375 EGLU_CHECK_CALL(egl, chooseConfig(m_display, attribList, &m_config, 1, &configCount));
377 TCU_CHECK(configCount != 0);
380 void MemoryStressCase::deinit (void)
383 m_allocator = DE_NULL;
385 if (m_display != EGL_NO_DISPLAY)
387 m_eglTestCtx.getLibrary().terminate(m_display);
388 m_display = EGL_NO_DISPLAY;
392 TestCase::IterateResult MemoryStressCase::iterate (void)
394 TestLog& log = m_testCtx.getLog();
396 if (m_iteration < m_iterationCount)
401 m_allocator = new MemoryAllocator(m_eglTestCtx, m_display, m_config, m_seed, m_spec.types, m_spec.minWidth, m_spec.minHeight, m_spec.maxWidth, m_spec.maxHeight, m_spec.use);
403 if (m_allocator->allocateUntilFailure())
405 log << TestLog::Message << "Couldn't exhaust memory before timeout. Allocated " << m_allocator->getAllocationCount() << " objects." << TestLog::EndMessage;
406 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
414 log << TestLog::Message << "Iteration " << m_iteration << ": Allocated " << m_allocator->getAllocationCount() << " objects; " << m_allocator->getContextCount() << " contexts, " << m_allocator->getPBufferCount() << " PBuffers." << TestLog::EndMessage;
415 log << TestLog::Message << "Got expected error: " << m_allocator->getErrorString() << TestLog::EndMessage;
416 m_allocationCounts.push_back(m_allocator->getAllocationCount());
426 log << TestLog::Message << "Iteration " << m_iteration << ": Allocated " << m_allocator->getAllocationCount() << " objects; " << m_allocator->getContextCount() << " contexts, " << m_allocator->getPBufferCount() << " PBuffers." << TestLog::EndMessage;
427 log << TestLog::Message << "Unexpected error" << TestLog::EndMessage;
433 // Analyze number of passed allocations.
434 int min = m_allocationCounts[0];
435 int max = m_allocationCounts[0];
437 float threshold = 50.0f;
439 for (int allocNdx = 0; allocNdx < (int)m_allocationCounts.size(); allocNdx++)
441 min = deMin32(m_allocationCounts[allocNdx], min);
442 max = deMax32(m_allocationCounts[allocNdx], max);
445 if (min == 0 && max != 0)
447 log << TestLog::Message << "Allocation count zero" << TestLog::EndMessage;
448 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
452 float change = (float)(min - max) / ((float)(max));
454 if (change > threshold)
456 log << TestLog::Message << "Allocated objects max: " << max << ", min: " << min << ", difference: " << change << "% threshold: " << threshold << "%" << TestLog::EndMessage;
457 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Allocation count variation");
460 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
467 MemoryStressTests::MemoryStressTests (EglTestContext& eglTestCtx)
468 : TestCaseGroup(eglTestCtx, "memory", "Memory allocation stress tests")
472 void MemoryStressTests::init (void)
474 // Check small pbuffers 256x256
476 MemoryStressCase::Spec spec;
478 spec.types = OBJECTTYPE_PBUFFER;
480 spec.minHeight = 256;
482 spec.maxHeight = 256;
485 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer_256x256", "PBuffer allocation stress tests"));
488 // Check small pbuffers 256x256 and use them
490 MemoryStressCase::Spec spec;
492 spec.types = OBJECTTYPE_PBUFFER;
494 spec.minHeight = 256;
496 spec.maxHeight = 256;
499 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer_256x256_use", "PBuffer allocation stress tests"));
502 // Check big pbuffers 1024x1024
504 MemoryStressCase::Spec spec;
506 spec.types = OBJECTTYPE_PBUFFER;
507 spec.minWidth = 1024;
508 spec.minHeight = 1024;
509 spec.maxWidth = 1024;
510 spec.maxHeight = 1024;
513 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer_1024x1024", "PBuffer allocation stress tests"));
516 // Check big pbuffers 1024x1024 and use them
518 MemoryStressCase::Spec spec;
520 spec.types = OBJECTTYPE_PBUFFER;
521 spec.minWidth = 1024;
522 spec.minHeight = 1024;
523 spec.maxWidth = 1024;
524 spec.maxHeight = 1024;
527 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer_1024x1024_use", "PBuffer allocation stress tests"));
530 // Check different sized pbuffers
532 MemoryStressCase::Spec spec;
534 spec.types = OBJECTTYPE_PBUFFER;
537 spec.maxWidth = 1024;
538 spec.maxHeight = 1024;
541 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer", "PBuffer allocation stress tests"));
544 // Check different sized pbuffers and use them
546 MemoryStressCase::Spec spec;
548 spec.types = OBJECTTYPE_PBUFFER;
551 spec.maxWidth = 1024;
552 spec.maxHeight = 1024;
555 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer_use", "PBuffer allocation stress tests"));
560 MemoryStressCase::Spec spec;
562 spec.types = OBJECTTYPE_CONTEXT;
563 spec.minWidth = 1024;
564 spec.minHeight = 1024;
565 spec.maxWidth = 1024;
566 spec.maxHeight = 1024;
569 addChild(new MemoryStressCase(m_eglTestCtx, spec, "context", "Context allocation stress tests"));
572 // Check contexts and use them
574 MemoryStressCase::Spec spec;
576 spec.types = OBJECTTYPE_CONTEXT;
577 spec.minWidth = 1024;
578 spec.minHeight = 1024;
579 spec.maxWidth = 1024;
580 spec.maxHeight = 1024;
583 addChild(new MemoryStressCase(m_eglTestCtx, spec, "context_use", "Context allocation stress tests"));
586 // Check contexts and pbuffers
588 MemoryStressCase::Spec spec;
590 spec.types = (ObjectType)(OBJECTTYPE_PBUFFER|OBJECTTYPE_CONTEXT);
593 spec.maxWidth = 1024;
594 spec.maxHeight = 1024;
597 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer_context", "PBuffer and context allocation stress tests"));
600 // Check contexts and pbuffers and use
602 MemoryStressCase::Spec spec;
604 spec.types = (ObjectType)(OBJECTTYPE_PBUFFER|OBJECTTYPE_CONTEXT);
607 spec.maxWidth = 1024;
608 spec.maxHeight = 1024;
611 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer_context_use", "PBuffer and context allocation stress tests"));