1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Tester Core
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 Render target info.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "tcuApp.hpp"
25 #include "tcuPlatform.hpp"
26 #include "tcuTestContext.hpp"
27 #include "tcuTestSessionExecutor.hpp"
28 #include "tcuTestHierarchyUtil.hpp"
29 #include "tcuCommandLine.hpp"
30 #include "tcuTestLog.hpp"
31 
32 #include "qpInfo.h"
33 #include "qpDebugOut.h"
34 
35 #include "deMath.h"
36 
37 #include <iostream>
38 
39 namespace tcu
40 {
41 
42 using std::string;
43 
44 /*--------------------------------------------------------------------*//*!
45  *  Writes all packages found stdout without any
46  *  separations. Recommended to be used with a single package
47  *  only. It's possible to use test selectors for limiting the export
48  *  to one package in a multipackage binary.
49  *//*--------------------------------------------------------------------*/
writeCaselistsToStdout(TestPackageRoot & root,TestContext & testCtx,const CommandLine & cmdLine)50 static void writeCaselistsToStdout (TestPackageRoot& root, TestContext& testCtx, const CommandLine& cmdLine)
51 {
52 	DefaultHierarchyInflater	inflater	(testCtx);
53 	TestHierarchyIterator		iter		(root, inflater, cmdLine);
54 
55 	while (iter.getState() != TestHierarchyIterator::STATE_FINISHED)
56 	{
57 		iter.next();
58 
59 		while (iter.getNode()->getNodeType() != NODETYPE_PACKAGE)
60 		{
61 			if (iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE)
62 				std::cout << (isTestNodeTypeExecutable(iter.getNode()->getNodeType()) ? "TEST" : "GROUP") << ": " << iter.getNodePath() << "\n";
63 			iter.next();
64 		}
65 
66 		DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE &&
67 				  iter.getNode()->getNodeType() == NODETYPE_PACKAGE);
68 		iter.next();
69 	}
70 }
71 
72 /*--------------------------------------------------------------------*//*!
73  * \brief Construct test application
74  *
75  * If a fatal error occurs during initialization constructor will call
76  * die() with debug information.
77  *
78  * \param platform Reference to platform implementation.
79  *//*--------------------------------------------------------------------*/
App(Platform & platform,Archive & archive,TestLog & log,const CommandLine & cmdLine)80 App::App (Platform& platform, Archive& archive, TestLog& log, const CommandLine& cmdLine)
81 	: m_platform		(platform)
82 	, m_watchDog		(DE_NULL)
83 	, m_crashHandler	(DE_NULL)
84 	, m_crashed			(false)
85 	, m_testCtx			(DE_NULL)
86 	, m_testRoot		(DE_NULL)
87 	, m_testExecutor	(DE_NULL)
88 {
89 	print("dEQP Core %s (0x%08x) starting..\n", qpGetReleaseName(), qpGetReleaseId());
90 	print("  target implementation = '%s'\n", qpGetTargetName());
91 
92 	if (!deSetRoundingMode(DE_ROUNDINGMODE_TO_NEAREST))
93 		qpPrintf("WARNING: Failed to set floating-point rounding mode!\n");
94 
95 	try
96 	{
97 		const RunMode	runMode	= cmdLine.getRunMode();
98 
99 		// Initialize watchdog
100 		if (cmdLine.isWatchDogEnabled())
101 			TCU_CHECK_INTERNAL(m_watchDog = qpWatchDog_create(onWatchdogTimeout, this, 300, 30));
102 
103 		// Initialize crash handler.
104 		if (cmdLine.isCrashHandlingEnabled())
105 			TCU_CHECK_INTERNAL(m_crashHandler = qpCrashHandler_create(onCrash, this));
106 
107 		// Create test context
108 		m_testCtx = new TestContext(m_platform, archive, log, cmdLine, m_watchDog);
109 
110 		// Create root from registry
111 		m_testRoot = new TestPackageRoot(*m_testCtx, TestPackageRegistry::getSingleton());
112 
113 		// \note No executor is created if runmode is not EXECUTE
114 		if (runMode == RUNMODE_EXECUTE)
115 			m_testExecutor = new TestSessionExecutor(*m_testRoot, *m_testCtx);
116 		else if (runMode == RUNMODE_DUMP_STDOUT_CASELIST)
117 			writeCaselistsToStdout(*m_testRoot, *m_testCtx, cmdLine);
118 		else if (runMode == RUNMODE_DUMP_XML_CASELIST)
119 			writeXmlCaselistsToFiles(*m_testRoot, *m_testCtx, cmdLine);
120 		else if (runMode == RUNMODE_DUMP_TEXT_CASELIST)
121 			writeTxtCaselistsToFiles(*m_testRoot, *m_testCtx, cmdLine);
122 		else
123 			DE_ASSERT(false);
124 	}
125 	catch (const std::exception& e)
126 	{
127 		cleanup();
128 		die("Failed to initialize dEQP: %s", e.what());
129 	}
130 }
131 
~App(void)132 App::~App (void)
133 {
134 	cleanup();
135 }
136 
cleanup(void)137 void App::cleanup (void)
138 {
139 	delete m_testExecutor;
140 	delete m_testRoot;
141 	delete m_testCtx;
142 
143 	if (m_crashHandler)
144 		qpCrashHandler_destroy(m_crashHandler);
145 
146 	if (m_watchDog)
147 		qpWatchDog_destroy(m_watchDog);
148 }
149 
150 /*--------------------------------------------------------------------*//*!
151  * \brief Step forward test execution
152  * \return true if application should call iterate() again and false
153  *         if test execution session is complete.
154  *//*--------------------------------------------------------------------*/
iterate(void)155 bool App::iterate (void)
156 {
157 	if (!m_testExecutor)
158 	{
159 		DE_ASSERT(m_testCtx->getCommandLine().getRunMode() != RUNMODE_EXECUTE);
160 		return false;
161 	}
162 
163 	// Poll platform events
164 	const bool platformOk = m_platform.processEvents();
165 
166 	// Iterate a step.
167 	bool testExecOk = false;
168 	if (platformOk)
169 	{
170 		try
171 		{
172 			testExecOk = m_testExecutor->iterate();
173 		}
174 		catch (const std::exception& e)
175 		{
176 			die("%s", e.what());
177 		}
178 	}
179 
180 	if (!platformOk || !testExecOk)
181 	{
182 		if (!platformOk)
183 			print("\nABORTED!\n");
184 		else
185 			print("\nDONE!\n");
186 
187 		const RunMode runMode = m_testCtx->getCommandLine().getRunMode();
188 		if (runMode == RUNMODE_EXECUTE)
189 		{
190 			const TestRunStatus& result = m_testExecutor->getStatus();
191 
192 			// Report statistics.
193 			print("\nTest run totals:\n");
194 			print("  Passed:        %d/%d (%.1f%%)\n", result.numPassed,		result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numPassed			/ (float)result.numExecuted) : 0.0f));
195 			print("  Failed:        %d/%d (%.1f%%)\n", result.numFailed,		result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numFailed			/ (float)result.numExecuted) : 0.0f));
196 			print("  Not supported: %d/%d (%.1f%%)\n", result.numNotSupported,	result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numNotSupported	/ (float)result.numExecuted) : 0.0f));
197 			print("  Warnings:      %d/%d (%.1f%%)\n", result.numWarnings,		result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numWarnings		/ (float)result.numExecuted) : 0.0f));
198 			if (!result.isComplete)
199 				print("Test run was ABORTED!\n");
200 		}
201 	}
202 
203 	return platformOk && testExecOk;
204 }
205 
onWatchdogTimeout(qpWatchDog * watchDog,void * userPtr)206 void App::onWatchdogTimeout (qpWatchDog* watchDog, void* userPtr)
207 {
208 	DE_UNREF(watchDog);
209 	static_cast<App*>(userPtr)->onWatchdogTimeout();
210 }
211 
onCrash(qpCrashHandler * crashHandler,void * userPtr)212 void App::onCrash (qpCrashHandler* crashHandler, void* userPtr)
213 {
214 	DE_UNREF(crashHandler);
215 	static_cast<App*>(userPtr)->onCrash();
216 }
217 
onWatchdogTimeout(void)218 void App::onWatchdogTimeout (void)
219 {
220 	if (!m_crashLock.tryLock() || m_crashed)
221 		return; // In crash handler already.
222 
223 	m_crashed = true;
224 
225 	m_testCtx->getLog().terminateCase(QP_TEST_RESULT_TIMEOUT);
226 	die("Watchdog timer timeout");
227 }
228 
writeCrashToLog(void * userPtr,const char * infoString)229 static void writeCrashToLog (void* userPtr, const char* infoString)
230 {
231 	// \note THIS IS CALLED BY SIGNAL HANDLER! CALLING MALLOC/FREE IS NOT ALLOWED!
232 	TestLog* log = static_cast<TestLog*>(userPtr);
233 	log->writeMessage(infoString);
234 }
235 
writeCrashToConsole(void * userPtr,const char * infoString)236 static void writeCrashToConsole (void* userPtr, const char* infoString)
237 {
238 	// \note THIS IS CALLED BY SIGNAL HANDLER! CALLING MALLOC/FREE IS NOT ALLOWED!
239 	DE_UNREF(userPtr);
240 	qpPrint(infoString);
241 }
242 
onCrash(void)243 void App::onCrash (void)
244 {
245 	// \note THIS IS CALLED BY SIGNAL HANDLER! CALLING MALLOC/FREE IS NOT ALLOWED!
246 
247 	if (!m_crashLock.tryLock() || m_crashed)
248 		return; // In crash handler already.
249 
250 	m_crashed = true;
251 
252 	bool isInCase = m_testExecutor ? m_testExecutor->isInTestCase() : false;
253 
254 	if (isInCase)
255 	{
256 		qpCrashHandler_writeCrashInfo(m_crashHandler, writeCrashToLog, &m_testCtx->getLog());
257 		m_testCtx->getLog().terminateCase(QP_TEST_RESULT_CRASH);
258 	}
259 	else
260 		qpCrashHandler_writeCrashInfo(m_crashHandler, writeCrashToConsole, DE_NULL);
261 
262 	die("Test program crashed");
263 }
264 
265 } // tcu
266