Merge "Remove tests affected by NV/OES_viewport_array extension" into nougat-cts...
[platform/upstream/VK-GL-CTS.git] / modules / egl / teglMemoryStressTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program EGL Module
3  * ---------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  *
19  *//*!
20  * \file
21  * \brief Memory object allocation stress tests
22  *//*--------------------------------------------------------------------*/
23
24 #include "teglMemoryStressTests.hpp"
25
26 #include "tcuTestLog.hpp"
27 #include "tcuCommandLine.hpp"
28
29 #include "deRandom.hpp"
30 #include "deClock.h"
31 #include "deString.h"
32
33 #include "gluDefs.hpp"
34 #include "glwFunctions.hpp"
35 #include "glwDefs.hpp"
36 #include "glwEnums.hpp"
37
38 #include "egluUtil.hpp"
39
40 #include "eglwLibrary.hpp"
41 #include "eglwEnums.hpp"
42
43 #include <vector>
44 #include <string>
45
46 using std::vector;
47 using std::string;
48 using tcu::TestLog;
49
50 using namespace eglw;
51
52 namespace deqp
53 {
54 namespace egl
55 {
56
57 namespace
58 {
59
60 enum ObjectType
61 {
62         OBJECTTYPE_PBUFFER = (1<<0),
63         OBJECTTYPE_CONTEXT = (1<<1),
64
65 //      OBJECTTYPE_WINDOW,
66 //      OBJECTTYPE_PIXMAP,
67 };
68
69 class MemoryAllocator
70 {
71 public:
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);
74
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;                                                    }
80
81 private:
82         void                    allocatePBuffer                 (void);
83         void                    allocateContext                 (void);
84
85         EglTestContext&                 m_eglTestCtx;
86         EGLDisplay                              m_display;
87         EGLConfig                               m_config;
88         glw::Functions                  m_gl;
89
90         de::Random                              m_rnd;
91         bool                                    m_failed;
92         string                                  m_errorString;
93
94         ObjectType                              m_types;
95         int                                             m_minWidth;
96         int                                             m_minHeight;
97         int                                             m_maxWidth;
98         int                                             m_maxHeight;
99         bool                                    m_use;
100
101         vector<EGLSurface>              m_pbuffers;
102         vector<EGLContext>              m_contexts;
103 };
104
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)
108         , m_config              (config)
109
110         , m_rnd                 (seed)
111         , m_failed              (false)
112
113         , m_types               (types)
114         , m_minWidth    (minWidth)
115         , m_minHeight   (minHeight)
116         , m_maxWidth    (maxWidth)
117         , m_maxHeight   (maxHeight)
118         , m_use                 (use)
119 {
120         m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
121 }
122
123 MemoryAllocator::~MemoryAllocator (void)
124 {
125         const Library& egl = m_eglTestCtx.getLibrary();
126
127         for (vector<EGLSurface>::const_iterator iter = m_pbuffers.begin(); iter != m_pbuffers.end(); ++iter)
128                 egl.destroySurface(m_display, *iter);
129
130         m_pbuffers.clear();
131
132         for (vector<EGLContext>::const_iterator iter = m_contexts.begin(); iter != m_contexts.end(); ++iter)
133                 egl.destroyContext(m_display, *iter);
134
135         m_contexts.clear();
136 }
137
138 bool MemoryAllocator::allocateUntilFailure (void)
139 {
140         const deUint64          timeLimitUs             = 10000000; // 10s
141         deUint64                        beginTimeUs             = deGetMicroseconds();
142         vector<ObjectType>      types;
143
144         if ((m_types & OBJECTTYPE_CONTEXT) != 0)
145                 types.push_back(OBJECTTYPE_CONTEXT);
146
147         if ((m_types & OBJECTTYPE_PBUFFER) != 0)
148                 types.push_back(OBJECTTYPE_PBUFFER);
149
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)
152         {
153                 allocateContext();
154                 allocatePBuffer();
155         }
156
157         while (!m_failed)
158         {
159                 ObjectType type = m_rnd.choose<ObjectType>(types.begin(), types.end());
160
161                 switch (type)
162                 {
163                         case OBJECTTYPE_PBUFFER:
164                                 allocatePBuffer();
165                                 break;
166
167                         case OBJECTTYPE_CONTEXT:
168                                 allocateContext();
169                                 break;
170
171                         default:
172                                 DE_ASSERT(false);
173                 }
174
175                 if (deGetMicroseconds() - beginTimeUs > timeLimitUs)
176                         return true;
177         }
178
179         return false;
180 }
181
182 void MemoryAllocator::allocatePBuffer (void)
183 {
184         // Reserve space for new allocations
185         try
186         {
187                 m_pbuffers.reserve(m_pbuffers.size() + 1);
188         }
189         catch (const std::bad_alloc&)
190         {
191                 m_errorString   = "std::bad_alloc when allocating more space for testcase. Out of host memory.";
192                 m_failed                = true;
193                 return;
194         }
195
196         // Allocate pbuffer
197         try
198         {
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[]    =
203                 {
204                         EGL_WIDTH,      width,
205                         EGL_HEIGHT, height,
206                         EGL_NONE
207                 };
208
209                 EGLSurface              surface                 = egl.createPbufferSurface(m_display, m_config, attribList);
210                 EGLU_CHECK_MSG(egl, "eglCreatePbufferSurface");
211
212                 DE_ASSERT(surface != EGL_NO_SURFACE);
213
214                 m_pbuffers.push_back(surface);
215
216                 if (m_use && m_contexts.size() > 0)
217                 {
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();
223
224                         EGLU_CHECK_CALL(egl, makeCurrent(m_display, surface, surface, context));
225
226                         m_gl.clearColor(red, green, blue, alpha);
227                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearColor()");
228
229                         m_gl.clear(GL_COLOR_BUFFER_BIT);
230                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClear()");
231
232                         EGLU_CHECK_CALL(egl, makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
233                 }
234         }
235         catch (const eglu::Error& error)
236         {
237                 if (error.getError() == EGL_BAD_ALLOC)
238                 {
239                         m_errorString   = "eglCreatePbufferSurface returned EGL_BAD_ALLOC";
240                         m_failed                = true;
241                         return;
242                 }
243                 else
244                         throw;
245         }
246 }
247
248 void MemoryAllocator::allocateContext (void)
249 {
250         // Reserve space for new allocations
251         try
252         {
253                 m_contexts.reserve(m_contexts.size() + 1);
254         }
255         catch (const std::bad_alloc&)
256         {
257                 m_errorString   = "std::bad_alloc when allocating more space for testcase. Out of host memory.";
258                 m_failed                = true;
259                 return;
260         }
261
262         // Allocate context
263         try
264         {
265                 const Library&  egl                             = m_eglTestCtx.getLibrary();
266                 const EGLint    attribList[]    =
267                 {
268                         EGL_CONTEXT_CLIENT_VERSION, 2,
269                         EGL_NONE
270                 };
271
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");
275
276                 DE_ASSERT(context != EGL_NO_CONTEXT);
277
278                 m_contexts.push_back(context);
279
280                 if (m_use && m_pbuffers.size() > 0)
281                 {
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();
287
288                         EGLU_CHECK_CALL(egl, makeCurrent(m_display, surface, surface, context));
289
290                         m_gl.clearColor(red, green, blue, alpha);
291                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClearColor()");
292
293                         m_gl.clear(GL_COLOR_BUFFER_BIT);
294                         GLU_EXPECT_NO_ERROR(m_gl.getError(), "glClear()");
295
296                         EGLU_CHECK_CALL(egl, makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
297                 }
298         }
299         catch (const eglu::Error& error)
300         {
301                 if (error.getError() == EGL_BAD_ALLOC)
302                 {
303                         m_errorString   = "eglCreateContext returned EGL_BAD_ALLOC";
304                         m_failed                = true;
305                         return;
306                 }
307                 else
308                         throw;
309         }
310 }
311
312 } // anonymous
313
314 class MemoryStressCase : public TestCase
315 {
316 public:
317         struct Spec
318         {
319                 ObjectType      types;
320                 int                     minWidth;
321                 int                     minHeight;
322                 int                     maxWidth;
323                 int                     maxHeight;
324                 bool            use;
325         };
326
327                                         MemoryStressCase        (EglTestContext& eglTestCtx, Spec spec, const char* name, const char* description);
328         void                    init                            (void);
329         void                    deinit                          (void);
330         IterateResult   iterate                         (void);
331
332 private:
333         Spec                            m_spec;
334         vector<int>                     m_allocationCounts;
335         MemoryAllocator*        m_allocator;
336
337         int                                     m_iteration;
338         int                                     m_iterationCount;
339         int                                     m_seed;
340         EGLDisplay                      m_display;
341         EGLConfig                       m_config;
342 };
343
344 MemoryStressCase::MemoryStressCase (EglTestContext& eglTestCtx, Spec spec, const char* name, const char* description)
345         : TestCase                      (eglTestCtx, name, description)
346         , m_spec                        (spec)
347         , m_allocator           (NULL)
348         , m_iteration           (0)
349         , m_iterationCount      (10)
350         , m_seed                        (deStringHash(name))
351         , m_display                     (EGL_NO_DISPLAY)
352         , m_config                      (DE_NULL)
353 {
354 }
355
356 void MemoryStressCase::init (void)
357 {
358         const Library&  egl                             = m_eglTestCtx.getLibrary();
359         EGLint                  configCount             = 0;
360         const EGLint    attribList[]    =
361         {
362                 EGL_SURFACE_TYPE,               EGL_PBUFFER_BIT,
363                 EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
364                 EGL_NONE
365         };
366
367         if (!m_testCtx.getCommandLine().isOutOfMemoryTestEnabled())
368         {
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");
371         }
372
373         m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
374
375         EGLU_CHECK_CALL(egl, chooseConfig(m_display, attribList, &m_config, 1, &configCount));
376
377         TCU_CHECK(configCount != 0);
378 }
379
380 void MemoryStressCase::deinit (void)
381 {
382         delete m_allocator;
383         m_allocator = DE_NULL;
384
385         if (m_display != EGL_NO_DISPLAY)
386         {
387                 m_eglTestCtx.getLibrary().terminate(m_display);
388                 m_display = EGL_NO_DISPLAY;
389         }
390 }
391
392 TestCase::IterateResult MemoryStressCase::iterate (void)
393 {
394         TestLog& log = m_testCtx.getLog();
395
396         if (m_iteration < m_iterationCount)
397         {
398                 try
399                 {
400                         if (!m_allocator)
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);
402
403                         if (m_allocator->allocateUntilFailure())
404                         {
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");
407
408                                 delete m_allocator;
409                                 m_allocator = NULL;
410
411                                 return STOP;
412                         }
413
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());
417
418                         delete m_allocator;
419                         m_allocator = NULL;
420
421                         m_iteration++;
422
423                         return CONTINUE;
424                 } catch (...)
425                 {
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;
428                         throw;
429                 }
430         }
431         else
432         {
433                 // Analyze number of passed allocations.
434                 int min = m_allocationCounts[0];
435                 int max = m_allocationCounts[0];
436
437                 float threshold = 50.0f;
438
439                 for (int allocNdx = 0; allocNdx < (int)m_allocationCounts.size(); allocNdx++)
440                 {
441                         min = deMin32(m_allocationCounts[allocNdx], min);
442                         max = deMax32(m_allocationCounts[allocNdx], max);
443                 }
444
445                 if (min == 0 && max != 0)
446                 {
447                         log << TestLog::Message << "Allocation count zero" << TestLog::EndMessage;
448                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
449                 }
450                 else
451                 {
452                         float change = (float)(min - max) / ((float)(max));
453
454                         if (change > threshold)
455                         {
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");
458                         }
459                         else
460                                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
461                 }
462
463                 return STOP;
464         }
465 }
466
467 MemoryStressTests::MemoryStressTests (EglTestContext& eglTestCtx)
468         : TestCaseGroup(eglTestCtx, "memory", "Memory allocation stress tests")
469 {
470 }
471
472 void MemoryStressTests::init (void)
473 {
474         // Check small pbuffers 256x256
475         {
476                 MemoryStressCase::Spec spec;
477
478                 spec.types              = OBJECTTYPE_PBUFFER;
479                 spec.minWidth   = 256;
480                 spec.minHeight  = 256;
481                 spec.maxWidth   = 256;
482                 spec.maxHeight  = 256;
483                 spec.use                = false;
484
485                 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer_256x256", "PBuffer allocation stress tests"));
486         }
487
488         // Check small pbuffers 256x256 and use them
489         {
490                 MemoryStressCase::Spec spec;
491
492                 spec.types              = OBJECTTYPE_PBUFFER;
493                 spec.minWidth   = 256;
494                 spec.minHeight  = 256;
495                 spec.maxWidth   = 256;
496                 spec.maxHeight  = 256;
497                 spec.use                = true;
498
499                 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer_256x256_use", "PBuffer allocation stress tests"));
500         }
501
502         // Check big pbuffers 1024x1024
503         {
504                 MemoryStressCase::Spec spec;
505
506                 spec.types              = OBJECTTYPE_PBUFFER;
507                 spec.minWidth   = 1024;
508                 spec.minHeight  = 1024;
509                 spec.maxWidth   = 1024;
510                 spec.maxHeight  = 1024;
511                 spec.use                = false;
512
513                 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer_1024x1024", "PBuffer allocation stress tests"));
514         }
515
516         // Check big pbuffers 1024x1024 and use them
517         {
518                 MemoryStressCase::Spec spec;
519
520                 spec.types              = OBJECTTYPE_PBUFFER;
521                 spec.minWidth   = 1024;
522                 spec.minHeight  = 1024;
523                 spec.maxWidth   = 1024;
524                 spec.maxHeight  = 1024;
525                 spec.use                = true;
526
527                 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer_1024x1024_use", "PBuffer allocation stress tests"));
528         }
529
530         // Check different sized pbuffers
531         {
532                 MemoryStressCase::Spec spec;
533
534                 spec.types              = OBJECTTYPE_PBUFFER;
535                 spec.minWidth   = 64;
536                 spec.minHeight  = 64;
537                 spec.maxWidth   = 1024;
538                 spec.maxHeight  = 1024;
539                 spec.use                = false;
540
541                 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer", "PBuffer allocation stress tests"));
542         }
543
544         // Check different sized pbuffers and use them
545         {
546                 MemoryStressCase::Spec spec;
547
548                 spec.types              = OBJECTTYPE_PBUFFER;
549                 spec.minWidth   = 64;
550                 spec.minHeight  = 64;
551                 spec.maxWidth   = 1024;
552                 spec.maxHeight  = 1024;
553                 spec.use                = true;
554
555                 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer_use", "PBuffer allocation stress tests"));
556         }
557
558         // Check contexts
559         {
560                 MemoryStressCase::Spec spec;
561
562                 spec.types              = OBJECTTYPE_CONTEXT;
563                 spec.minWidth   = 1024;
564                 spec.minHeight  = 1024;
565                 spec.maxWidth   = 1024;
566                 spec.maxHeight  = 1024;
567                 spec.use                = false;
568
569                 addChild(new MemoryStressCase(m_eglTestCtx, spec, "context", "Context allocation stress tests"));
570         }
571
572         // Check contexts and use them
573         {
574                 MemoryStressCase::Spec spec;
575
576                 spec.types              = OBJECTTYPE_CONTEXT;
577                 spec.minWidth   = 1024;
578                 spec.minHeight  = 1024;
579                 spec.maxWidth   = 1024;
580                 spec.maxHeight  = 1024;
581                 spec.use                = true;
582
583                 addChild(new MemoryStressCase(m_eglTestCtx, spec, "context_use", "Context allocation stress tests"));
584         }
585
586         // Check contexts and pbuffers
587         {
588                 MemoryStressCase::Spec spec;
589
590                 spec.types              = (ObjectType)(OBJECTTYPE_PBUFFER|OBJECTTYPE_CONTEXT);
591                 spec.minWidth   = 64;
592                 spec.minHeight  = 64;
593                 spec.maxWidth   = 1024;
594                 spec.maxHeight  = 1024;
595                 spec.use                = false;
596
597                 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer_context", "PBuffer and context allocation stress tests"));
598         }
599
600         // Check contexts and pbuffers and use
601         {
602                 MemoryStressCase::Spec spec;
603
604                 spec.types              = (ObjectType)(OBJECTTYPE_PBUFFER|OBJECTTYPE_CONTEXT);
605                 spec.minWidth   = 64;
606                 spec.minHeight  = 64;
607                 spec.maxWidth   = 1024;
608                 spec.maxHeight  = 1024;
609                 spec.use                = true;
610
611                 addChild(new MemoryStressCase(m_eglTestCtx, spec, "pbuffer_context_use", "PBuffer and context allocation stress tests"));
612         }
613 }
614
615 } // egl
616 } // deqp