1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) 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 State change performance tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "glsStateChangePerfTestCases.hpp"
25
26 #include "tcuTestLog.hpp"
27
28 #include "gluDefs.hpp"
29 #include "gluRenderContext.hpp"
30 #include "gluShaderProgram.hpp"
31
32 #include "glwFunctions.hpp"
33 #include "glwEnums.hpp"
34
35 #include "deStringUtil.hpp"
36
37 #include "deClock.h"
38
39 #include <vector>
40 #include <algorithm>
41
42 using std::string;
43 using std::vector;
44 using tcu::TestLog;
45 using namespace glw;
46
47 namespace deqp
48 {
49 namespace gls
50 {
51
52 namespace
53 {
54
55 struct ResultStats
56 {
57 double median;
58 double mean;
59 double variance;
60
61 uint64_t min;
62 uint64_t max;
63 };
64
calculateStats(const vector<uint64_t> & values)65 ResultStats calculateStats(const vector<uint64_t> &values)
66 {
67 ResultStats result = {0.0, 0.0, 0.0, 0xFFFFFFFFFFFFFFFFu, 0};
68
69 uint64_t sum = 0;
70
71 for (int i = 0; i < (int)values.size(); i++)
72 sum += values[i];
73
74 result.mean = ((double)sum) / (double)values.size();
75
76 for (int i = 0; i < (int)values.size(); i++)
77 {
78 const double val = (double)values[i];
79 result.variance += (val - result.mean) * (val - result.mean);
80 }
81
82 result.variance /= (double)values.size();
83
84 {
85 const int n = (int)(values.size() / 2);
86
87 vector<uint64_t> sortedValues = values;
88
89 std::sort(sortedValues.begin(), sortedValues.end());
90
91 result.median = (double)sortedValues[n];
92 }
93
94 for (int i = 0; i < (int)values.size(); i++)
95 {
96 result.min = std::min(result.min, values[i]);
97 result.max = std::max(result.max, values[i]);
98 }
99
100 return result;
101 }
102
genIndices(vector<GLushort> & indices,int triangleCount)103 void genIndices(vector<GLushort> &indices, int triangleCount)
104 {
105 indices.reserve(triangleCount * 3);
106
107 for (int triangleNdx = 0; triangleNdx < triangleCount; triangleNdx++)
108 {
109 indices.push_back((GLushort)(triangleNdx * 3));
110 indices.push_back((GLushort)(triangleNdx * 3 + 1));
111 indices.push_back((GLushort)(triangleNdx * 3 + 2));
112 }
113 }
114
genCoords(vector<GLfloat> & coords,int triangleCount)115 void genCoords(vector<GLfloat> &coords, int triangleCount)
116 {
117 coords.reserve(triangleCount * 3 * 2);
118
119 for (int triangleNdx = 0; triangleNdx < triangleCount; triangleNdx++)
120 {
121 if ((triangleNdx % 2) == 0)
122 {
123 // CW
124 coords.push_back(-1.0f);
125 coords.push_back(-1.0f);
126
127 coords.push_back(1.0f);
128 coords.push_back(-1.0f);
129
130 coords.push_back(1.0f);
131 coords.push_back(1.0f);
132 }
133 else
134 {
135 // CCW
136 coords.push_back(-1.0f);
137 coords.push_back(-1.0f);
138
139 coords.push_back(-1.0f);
140 coords.push_back(1.0f);
141
142 coords.push_back(1.0f);
143 coords.push_back(1.0f);
144 }
145 }
146 }
147
genTextureData(vector<uint8_t> & data,int width,int height)148 void genTextureData(vector<uint8_t> &data, int width, int height)
149 {
150 data.clear();
151 data.reserve(width * height * 4);
152
153 for (int x = 0; x < width; x++)
154 {
155 for (int y = 0; y < height; y++)
156 {
157 data.push_back((uint8_t)((255 * x) / width));
158 data.push_back((uint8_t)((255 * y) / width));
159 data.push_back((uint8_t)((255 * x * y) / (width * height)));
160 data.push_back(255);
161 }
162 }
163 }
164
calculateVariance(const vector<uint64_t> & values,double avg)165 double calculateVariance(const vector<uint64_t> &values, double avg)
166 {
167 double sum = 0.0;
168
169 for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++)
170 {
171 double value = (double)values[valueNdx];
172 sum += (value - avg) * (value - avg);
173 }
174
175 return sum / (double)values.size();
176 }
177
findMin(const vector<uint64_t> & values)178 uint64_t findMin(const vector<uint64_t> &values)
179 {
180 uint64_t min = ~0ull;
181
182 for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++)
183 min = std::min(values[valueNdx], min);
184
185 return min;
186 }
187
findMax(const vector<uint64_t> & values)188 uint64_t findMax(const vector<uint64_t> &values)
189 {
190 uint64_t max = 0;
191
192 for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++)
193 max = std::max(values[valueNdx], max);
194
195 return max;
196 }
197
findMedian(const vector<uint64_t> & v)198 uint64_t findMedian(const vector<uint64_t> &v)
199 {
200 vector<uint64_t> values = v;
201 size_t n = values.size() / 2;
202
203 std::nth_element(values.begin(), values.begin() + n, values.end());
204
205 return values[n];
206 }
207
208 } // namespace
209
StateChangePerformanceCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * description,DrawType drawType,int drawCallCount,int triangleCount)210 StateChangePerformanceCase::StateChangePerformanceCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
211 const char *name, const char *description, DrawType drawType,
212 int drawCallCount, int triangleCount)
213 : tcu::TestCase(testCtx, tcu::NODETYPE_PERFORMANCE, name, description)
214 , m_renderCtx(renderCtx)
215 , m_drawType(drawType)
216 , m_iterationCount(100)
217 , m_callCount(drawCallCount)
218 , m_triangleCount(triangleCount)
219 {
220 }
221
~StateChangePerformanceCase(void)222 StateChangePerformanceCase::~StateChangePerformanceCase(void)
223 {
224 StateChangePerformanceCase::deinit();
225 }
226
init(void)227 void StateChangePerformanceCase::init(void)
228 {
229 if (m_drawType == DRAWTYPE_INDEXED_USER_PTR)
230 genIndices(m_indices, m_triangleCount);
231 }
232
requireIndexBuffers(int count)233 void StateChangePerformanceCase::requireIndexBuffers(int count)
234 {
235 const glw::Functions &gl = m_renderCtx.getFunctions();
236
237 if ((int)m_indexBuffers.size() >= count)
238 return;
239
240 m_indexBuffers.reserve(count);
241
242 vector<GLushort> indices;
243 genIndices(indices, m_triangleCount);
244
245 while ((int)m_indexBuffers.size() < count)
246 {
247 GLuint buffer;
248
249 gl.genBuffers(1, &buffer);
250 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers()");
251
252 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
253 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
254 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)(indices.size() * sizeof(GLushort)), &(indices[0]),
255 GL_STATIC_DRAW);
256 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData()");
257 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
258 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
259
260 m_indexBuffers.push_back(buffer);
261 }
262 }
263
requireCoordBuffers(int count)264 void StateChangePerformanceCase::requireCoordBuffers(int count)
265 {
266 const glw::Functions &gl = m_renderCtx.getFunctions();
267
268 if ((int)m_coordBuffers.size() >= count)
269 return;
270
271 m_coordBuffers.reserve(count);
272
273 vector<GLfloat> coords;
274 genCoords(coords, m_triangleCount);
275
276 while ((int)m_coordBuffers.size() < count)
277 {
278 GLuint buffer;
279
280 gl.genBuffers(1, &buffer);
281 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers()");
282
283 gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
284 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
285 gl.bufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(coords.size() * sizeof(GLfloat)), &(coords[0]), GL_STATIC_DRAW);
286 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData()");
287 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
288 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
289
290 m_coordBuffers.push_back(buffer);
291 }
292 }
293
requirePrograms(int count)294 void StateChangePerformanceCase::requirePrograms(int count)
295 {
296 if ((int)m_programs.size() >= count)
297 return;
298
299 m_programs.reserve(count);
300
301 while ((int)m_programs.size() < count)
302 {
303 string vertexShaderSource = "attribute mediump vec2 a_coord;\n"
304 "varying mediump vec2 v_texCoord;\n"
305 "void main (void)\n"
306 "{\n"
307 "\tv_texCoord = vec2(0.5) + 0.5" +
308 de::toString(m_programs.size()) +
309 " * a_coord.xy;\n"
310 "\tgl_Position = vec4(a_coord, 0.5, 1.0);\n"
311 "}";
312
313 string fragmentShaderSource = "uniform sampler2D u_sampler;\n"
314 "varying mediump vec2 v_texCoord;\n"
315 "void main (void)\n"
316 "{\n"
317 "\tgl_FragColor = vec4(1.0" +
318 de::toString(m_programs.size()) +
319 " * texture2D(u_sampler, v_texCoord).xyz, 1.0);\n"
320 "}";
321
322 glu::ShaderProgram *program =
323 new glu::ShaderProgram(m_renderCtx, glu::ProgramSources() << glu::VertexSource(vertexShaderSource)
324 << glu::FragmentSource(fragmentShaderSource));
325
326 if (!program->isOk())
327 {
328 m_testCtx.getLog() << *program;
329 delete program;
330 TCU_FAIL("Compile failed");
331 }
332
333 m_programs.push_back(program);
334 }
335 }
336
requireTextures(int count)337 void StateChangePerformanceCase::requireTextures(int count)
338 {
339 const glw::Functions &gl = m_renderCtx.getFunctions();
340
341 const int textureWidth = 64;
342 const int textureHeight = 64;
343
344 if ((int)m_textures.size() >= count)
345 return;
346
347 m_textures.reserve(count);
348
349 vector<uint8_t> textureData;
350 genTextureData(textureData, textureWidth, textureHeight);
351
352 DE_ASSERT(textureData.size() == textureWidth * textureHeight * 4);
353
354 while ((int)m_textures.size() < count)
355 {
356 GLuint texture;
357
358 gl.genTextures(1, &texture);
359 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures()");
360
361 gl.bindTexture(GL_TEXTURE_2D, texture);
362 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture()");
363
364 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
365 &(textureData[0]));
366 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexImage2D()");
367
368 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
369 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri()");
370 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
371 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri()");
372 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
373 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri()");
374 gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
375 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri()");
376
377 gl.bindTexture(GL_TEXTURE_2D, 0);
378 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture()");
379
380 m_textures.push_back(texture);
381 }
382 }
383
requireFramebuffers(int count)384 void StateChangePerformanceCase::requireFramebuffers(int count)
385 {
386 const glw::Functions &gl = m_renderCtx.getFunctions();
387
388 if ((int)m_framebuffers.size() >= count)
389 return;
390
391 m_framebuffers.reserve(count);
392
393 requireRenderbuffers(count);
394
395 while ((int)m_framebuffers.size() < count)
396 {
397 GLuint framebuffer;
398
399 gl.genFramebuffers(1, &framebuffer);
400 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers()");
401
402 gl.bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
403 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer()");
404
405 gl.bindRenderbuffer(GL_RENDERBUFFER, m_renderbuffers[m_framebuffers.size()]);
406 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer()");
407
408 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
409 m_renderbuffers[m_framebuffers.size()]);
410 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer()");
411
412 gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
413 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer()");
414
415 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
416 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer()");
417
418 m_framebuffers.push_back(framebuffer);
419 }
420 }
421
requireRenderbuffers(int count)422 void StateChangePerformanceCase::requireRenderbuffers(int count)
423 {
424 const glw::Functions &gl = m_renderCtx.getFunctions();
425
426 if ((int)m_renderbuffers.size() >= count)
427 return;
428
429 m_renderbuffers.reserve(count);
430
431 while ((int)m_renderbuffers.size() < count)
432 {
433 GLuint renderbuffer;
434
435 gl.genRenderbuffers(1, &renderbuffer);
436 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers()");
437
438 gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
439 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer()");
440
441 gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGB565, 24, 24);
442 GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage()");
443
444 gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
445 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer()");
446
447 m_renderbuffers.push_back(renderbuffer);
448 }
449 }
450
requireSamplers(int count)451 void StateChangePerformanceCase::requireSamplers(int count)
452 {
453 const glw::Functions &gl = m_renderCtx.getFunctions();
454
455 if ((int)m_samplers.size() >= count)
456 return;
457
458 m_samplers.reserve(count);
459
460 while ((int)m_samplers.size() < count)
461 {
462 GLuint sampler;
463 gl.genSamplers(1, &sampler);
464 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenSamplers()");
465 m_samplers.push_back(sampler);
466 }
467 }
468
requireVertexArrays(int count)469 void StateChangePerformanceCase::requireVertexArrays(int count)
470 {
471 const glw::Functions &gl = m_renderCtx.getFunctions();
472
473 if ((int)m_vertexArrays.size() >= count)
474 return;
475
476 m_vertexArrays.reserve(count);
477
478 while ((int)m_vertexArrays.size() < count)
479 {
480 GLuint vertexArray;
481 gl.genVertexArrays(1, &vertexArray);
482 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays()");
483 m_vertexArrays.push_back(vertexArray);
484 }
485 }
486
deinit(void)487 void StateChangePerformanceCase::deinit(void)
488 {
489 m_indices.clear();
490 m_interleavedResults.clear();
491 m_batchedResults.clear();
492
493 {
494 const glw::Functions &gl = m_renderCtx.getFunctions();
495
496 if (!m_indexBuffers.empty())
497 {
498 gl.deleteBuffers((GLsizei)m_indexBuffers.size(), &(m_indexBuffers[0]));
499 m_indexBuffers.clear();
500 }
501
502 if (!m_coordBuffers.empty())
503 {
504 gl.deleteBuffers((GLsizei)m_coordBuffers.size(), &(m_coordBuffers[0]));
505 m_coordBuffers.clear();
506 }
507
508 if (!m_textures.empty())
509 {
510 gl.deleteTextures((GLsizei)m_textures.size(), &(m_textures[0]));
511 m_textures.clear();
512 }
513
514 if (!m_framebuffers.empty())
515 {
516 gl.deleteFramebuffers((GLsizei)m_framebuffers.size(), &(m_framebuffers[0]));
517 m_framebuffers.clear();
518 }
519
520 if (!m_renderbuffers.empty())
521 {
522 gl.deleteRenderbuffers((GLsizei)m_renderbuffers.size(), &(m_renderbuffers[0]));
523 m_renderbuffers.clear();
524 }
525
526 if (!m_samplers.empty())
527 {
528 gl.deleteSamplers((GLsizei)m_samplers.size(), &m_samplers[0]);
529 m_samplers.clear();
530 }
531
532 if (!m_vertexArrays.empty())
533 {
534 gl.deleteVertexArrays((GLsizei)m_vertexArrays.size(), &m_vertexArrays[0]);
535 m_vertexArrays.clear();
536 }
537
538 for (int programNdx = 0; programNdx < (int)m_programs.size(); programNdx++)
539 {
540 delete m_programs[programNdx];
541 m_programs[programNdx] = NULL;
542 }
543 m_programs.clear();
544 }
545 }
546
logAndSetTestResult(void)547 void StateChangePerformanceCase::logAndSetTestResult(void)
548 {
549 TestLog &log = m_testCtx.getLog();
550
551 ResultStats interleaved = calculateStats(m_interleavedResults);
552 ResultStats batched = calculateStats(m_batchedResults);
553
554 log << TestLog::Message << "Interleaved mean: " << interleaved.mean << TestLog::EndMessage;
555 log << TestLog::Message << "Interleaved median: " << interleaved.median << TestLog::EndMessage;
556 log << TestLog::Message << "Interleaved variance: " << interleaved.variance << TestLog::EndMessage;
557 log << TestLog::Message << "Interleaved min: " << interleaved.min << TestLog::EndMessage;
558 log << TestLog::Message << "Interleaved max: " << interleaved.max << TestLog::EndMessage;
559
560 log << TestLog::Message << "Batched mean: " << batched.mean << TestLog::EndMessage;
561 log << TestLog::Message << "Batched median: " << batched.median << TestLog::EndMessage;
562 log << TestLog::Message << "Batched variance: " << batched.variance << TestLog::EndMessage;
563 log << TestLog::Message << "Batched min: " << batched.min << TestLog::EndMessage;
564 log << TestLog::Message << "Batched max: " << batched.max << TestLog::EndMessage;
565
566 log << TestLog::Message << "Batched/Interleaved mean ratio: " << (interleaved.mean / batched.mean)
567 << TestLog::EndMessage;
568 log << TestLog::Message << "Batched/Interleaved median ratio: " << (interleaved.median / batched.median)
569 << TestLog::EndMessage;
570
571 m_testCtx.setTestResult(QP_TEST_RESULT_PASS,
572 de::floatToString((float)(((double)interleaved.median) / batched.median), 2).c_str());
573 }
574
iterate(void)575 tcu::TestCase::IterateResult StateChangePerformanceCase::iterate(void)
576 {
577 if (m_interleavedResults.empty() && m_batchedResults.empty())
578 {
579 TestLog &log = m_testCtx.getLog();
580
581 log << TestLog::Message << "Draw call count: " << m_callCount << TestLog::EndMessage;
582 log << TestLog::Message << "Per call triangle count: " << m_triangleCount << TestLog::EndMessage;
583 }
584
585 // \note [mika] Interleave sampling to balance effects of powerstate etc.
586 if ((int)m_interleavedResults.size() < m_iterationCount && m_batchedResults.size() >= m_interleavedResults.size())
587 {
588 const glw::Functions &gl = m_renderCtx.getFunctions();
589 uint64_t resBeginUs = 0;
590 uint64_t resEndUs = 0;
591
592 setupInitialState(gl);
593 gl.finish();
594 GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish()");
595
596 // Render result
597 resBeginUs = deGetMicroseconds();
598
599 renderTest(gl);
600
601 gl.finish();
602 resEndUs = deGetMicroseconds();
603 GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish()");
604
605 m_interleavedResults.push_back(resEndUs - resBeginUs);
606
607 return CONTINUE;
608 }
609 else if ((int)m_batchedResults.size() < m_iterationCount)
610 {
611 const glw::Functions &gl = m_renderCtx.getFunctions();
612 uint64_t refBeginUs = 0;
613 uint64_t refEndUs = 0;
614
615 setupInitialState(gl);
616 gl.finish();
617 GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish()");
618
619 // Render reference
620 refBeginUs = deGetMicroseconds();
621
622 renderReference(gl);
623
624 gl.finish();
625 refEndUs = deGetMicroseconds();
626 GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish()");
627
628 m_batchedResults.push_back(refEndUs - refBeginUs);
629
630 return CONTINUE;
631 }
632 else
633 {
634 logAndSetTestResult();
635 return STOP;
636 }
637 }
638
callDraw(const glw::Functions & gl)639 void StateChangePerformanceCase::callDraw(const glw::Functions &gl)
640 {
641 switch (m_drawType)
642 {
643 case DRAWTYPE_NOT_INDEXED:
644 gl.drawArrays(GL_TRIANGLES, 0, m_triangleCount * 3);
645 break;
646 case DRAWTYPE_INDEXED_USER_PTR:
647 gl.drawElements(GL_TRIANGLES, m_triangleCount * 3, GL_UNSIGNED_SHORT, &m_indices[0]);
648 break;
649 case DRAWTYPE_INDEXED_BUFFER:
650 gl.drawElements(GL_TRIANGLES, m_triangleCount * 3, GL_UNSIGNED_SHORT, NULL);
651 break;
652 default:
653 DE_ASSERT(false);
654 }
655 }
656
657 // StateChangeCallPerformanceCase
658
StateChangeCallPerformanceCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * description)659 StateChangeCallPerformanceCase::StateChangeCallPerformanceCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
660 const char *name, const char *description)
661 : tcu::TestCase(testCtx, tcu::NODETYPE_PERFORMANCE, name, description)
662 , m_renderCtx(renderCtx)
663 , m_iterationCount(100)
664 , m_callCount(1000)
665 {
666 }
667
~StateChangeCallPerformanceCase(void)668 StateChangeCallPerformanceCase::~StateChangeCallPerformanceCase(void)
669 {
670 }
671
executeTest(void)672 void StateChangeCallPerformanceCase::executeTest(void)
673 {
674 const glw::Functions &gl = m_renderCtx.getFunctions();
675 uint64_t beginTimeUs = 0;
676 uint64_t endTimeUs = 0;
677
678 beginTimeUs = deGetMicroseconds();
679
680 execCalls(gl, (int)m_results.size(), m_callCount);
681
682 endTimeUs = deGetMicroseconds();
683
684 m_results.push_back(endTimeUs - beginTimeUs);
685 }
686
logTestCase(void)687 void StateChangeCallPerformanceCase::logTestCase(void)
688 {
689 TestLog &log = m_testCtx.getLog();
690
691 log << TestLog::Message << "Iteration count: " << m_iterationCount << TestLog::EndMessage;
692 log << TestLog::Message << "Per iteration call count: " << m_callCount << TestLog::EndMessage;
693 }
694
calculateAverage(const vector<uint64_t> & values)695 double calculateAverage(const vector<uint64_t> &values)
696 {
697 uint64_t sum = 0;
698
699 for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++)
700 sum += values[valueNdx];
701
702 return ((double)sum) / (double)values.size();
703 }
704
logAndSetTestResult(void)705 void StateChangeCallPerformanceCase::logAndSetTestResult(void)
706 {
707 TestLog &log = m_testCtx.getLog();
708
709 uint64_t minUs = findMin(m_results);
710 uint64_t maxUs = findMax(m_results);
711 uint64_t medianUs = findMedian(m_results);
712 double avgIterationUs = calculateAverage(m_results);
713 double avgCallUs = avgIterationUs / m_callCount;
714 double varIteration = calculateVariance(m_results, avgIterationUs);
715 double avgMedianCallUs = ((double)medianUs) / m_callCount;
716
717 log << TestLog::Message << "Min iteration time: " << minUs << "us" << TestLog::EndMessage;
718 log << TestLog::Message << "Max iteration time: " << maxUs << "us" << TestLog::EndMessage;
719 log << TestLog::Message << "Average iteration time: " << avgIterationUs << "us" << TestLog::EndMessage;
720 log << TestLog::Message << "Iteration variance time: " << varIteration << TestLog::EndMessage;
721 log << TestLog::Message << "Median iteration time: " << medianUs << "us" << TestLog::EndMessage;
722 log << TestLog::Message << "Average call time: " << avgCallUs << "us" << TestLog::EndMessage;
723 log << TestLog::Message << "Average call time for median iteration: " << avgMedianCallUs << "us"
724 << TestLog::EndMessage;
725
726 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString((float)avgMedianCallUs, 3).c_str());
727 }
728
iterate(void)729 tcu::TestCase::IterateResult StateChangeCallPerformanceCase::iterate(void)
730 {
731 if (m_results.empty())
732 logTestCase();
733
734 if ((int)m_results.size() < m_iterationCount)
735 {
736 executeTest();
737 GLU_EXPECT_NO_ERROR(m_renderCtx.getFunctions().getError(), "Unexpected error");
738 return CONTINUE;
739 }
740 else
741 {
742 logAndSetTestResult();
743 return STOP;
744 }
745 }
746
747 } // namespace gls
748 } // namespace deqp
749