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