• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)50 static void writeCaselistsToStdout (TestPackageRoot& root, TestContext& testCtx)
51 {
52 	DefaultHierarchyInflater			inflater		(testCtx);
53 	de::MovePtr<const CaseListFilter>	caseListFilter	(testCtx.getCommandLine().createCaseListFilter(testCtx.getArchive()));
54 	TestHierarchyIterator				iter			(root, inflater, *caseListFilter);
55 
56 	while (iter.getState() != TestHierarchyIterator::STATE_FINISHED)
57 	{
58 		iter.next();
59 
60 		while (iter.getNode()->getNodeType() != NODETYPE_PACKAGE)
61 		{
62 			if (iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE)
63 				std::cout << (isTestNodeTypeExecutable(iter.getNode()->getNodeType()) ? "TEST" : "GROUP") << ": " << iter.getNodePath() << "\n";
64 			iter.next();
65 		}
66 
67 		DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE &&
68 				  iter.getNode()->getNodeType() == NODETYPE_PACKAGE);
69 		iter.next();
70 	}
71 }
72 
73 
74 /*--------------------------------------------------------------------*//*!
75  * Verifies that amber capability requirements in the .amber files
76  * match with capabilities defined on the CTS C code.
77  *//*--------------------------------------------------------------------*/
verifyAmberCapabilityCoherency(TestPackageRoot & root,TestContext & testCtx)78 static void verifyAmberCapabilityCoherency (TestPackageRoot& root, TestContext& testCtx)
79 {
80 	DefaultHierarchyInflater			inflater(testCtx);
81 	de::MovePtr<const CaseListFilter>	caseListFilter(testCtx.getCommandLine().createCaseListFilter(testCtx.getArchive()));
82 	TestHierarchyIterator				iter(root, inflater, *caseListFilter);
83 	int									count = 0;
84 	int									errorCount = 0;
85 
86 	bool ok = true;
87 
88 	while (iter.getState() != TestHierarchyIterator::STATE_FINISHED)
89 	{
90 		iter.next();
91 
92 		while (iter.getNode()->getNodeType() != NODETYPE_PACKAGE)
93 		{
94 			if (iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE &&
95 				isTestNodeTypeExecutable(iter.getNode()->getNodeType()))
96 			{
97 				std::cout << iter.getNodePath() << "\n";
98 				testCtx.getLog() << tcu::TestLog::Message << iter.getNodePath() << tcu::TestLog::EndMessage;
99 				if (!iter.getNode()->validateRequirements())
100 				{
101 					ok = false;
102 					errorCount++;
103 				}
104 				count++;
105 			}
106 			iter.next();
107 		}
108 
109 		DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE &&
110 			iter.getNode()->getNodeType() == NODETYPE_PACKAGE);
111 		iter.next();
112 	}
113 	std::cout << count << " amber tests, " << errorCount << " errors.\n";
114 	if (!ok)
115 		TCU_THROW(InternalError, "One or more CTS and Amber test requirements do not match; check log for details");
116 
117 }
118 
119 /*--------------------------------------------------------------------*//*!
120  * \brief Construct test application
121  *
122  * If a fatal error occurs during initialization constructor will call
123  * die() with debug information.
124  *
125  * \param platform Reference to platform implementation.
126  *//*--------------------------------------------------------------------*/
App(Platform & platform,Archive & archive,TestLog & log,const CommandLine & cmdLine)127 App::App (Platform& platform, Archive& archive, TestLog& log, const CommandLine& cmdLine)
128 	: m_platform		(platform)
129 	, m_watchDog		(DE_NULL)
130 	, m_crashHandler	(DE_NULL)
131 	, m_crashed			(false)
132 	, m_testCtx			(DE_NULL)
133 	, m_testRoot		(DE_NULL)
134 	, m_testExecutor	(DE_NULL)
135 {
136 	if (!cmdLine.isSubProcess())
137 	{
138 		print("dEQP Core %s (0x%08x) starting..\n", qpGetReleaseName(), qpGetReleaseId());
139 		print("  target implementation = '%s'\n", qpGetTargetName());
140 	}
141 
142 	if (!deSetRoundingMode(DE_ROUNDINGMODE_TO_NEAREST_EVEN))
143 		qpPrintf("WARNING: Failed to set floating-point rounding mode!\n");
144 
145 	try
146 	{
147 		const RunMode	runMode	= cmdLine.getRunMode();
148 
149 		// Initialize watchdog
150 		if (cmdLine.isWatchDogEnabled())
151 			TCU_CHECK_INTERNAL(m_watchDog = qpWatchDog_create(onWatchdogTimeout, this, WATCHDOG_TOTAL_TIME_LIMIT_SECS, WATCHDOG_INTERVAL_TIME_LIMIT_SECS));
152 
153 		// Initialize crash handler.
154 		if (cmdLine.isCrashHandlingEnabled())
155 			TCU_CHECK_INTERNAL(m_crashHandler = qpCrashHandler_create(onCrash, this));
156 
157 		// Create test context
158 		m_testCtx = new TestContext(m_platform, archive, log, cmdLine, m_watchDog);
159 
160 		// Create root from registry
161 		m_testRoot = new TestPackageRoot(*m_testCtx, TestPackageRegistry::getSingleton());
162 
163 		// \note No executor is created if runmode is not EXECUTE
164 		if (runMode == RUNMODE_EXECUTE)
165 			m_testExecutor = new TestSessionExecutor(*m_testRoot, *m_testCtx);
166 		else if (runMode == RUNMODE_DUMP_STDOUT_CASELIST)
167 			writeCaselistsToStdout(*m_testRoot, *m_testCtx);
168 		else if (runMode == RUNMODE_DUMP_XML_CASELIST)
169 			writeXmlCaselistsToFiles(*m_testRoot, *m_testCtx, cmdLine);
170 		else if (runMode == RUNMODE_DUMP_TEXT_CASELIST)
171 			writeTxtCaselistsToFiles(*m_testRoot, *m_testCtx, cmdLine);
172 		else if (runMode == RUNMODE_VERIFY_AMBER_COHERENCY)
173 			verifyAmberCapabilityCoherency(*m_testRoot, *m_testCtx);
174 		else
175 			DE_ASSERT(false);
176 	}
177 	catch (const std::exception& e)
178 	{
179 		cleanup();
180 		die("Failed to initialize dEQP: %s", e.what());
181 	}
182 }
183 
~App(void)184 App::~App (void)
185 {
186 	cleanup();
187 }
188 
cleanup(void)189 void App::cleanup (void)
190 {
191 	delete m_testExecutor;
192 	delete m_testRoot;
193 	delete m_testCtx;
194 
195 	if (m_crashHandler)
196 		qpCrashHandler_destroy(m_crashHandler);
197 
198 	if (m_watchDog)
199 		qpWatchDog_destroy(m_watchDog);
200 }
201 
202 /*--------------------------------------------------------------------*//*!
203  * \brief Step forward test execution
204  * \return true if application should call iterate() again and false
205  *         if test execution session is complete.
206  *//*--------------------------------------------------------------------*/
iterate(void)207 bool App::iterate (void)
208 {
209 	if (!m_testExecutor)
210 	{
211 		DE_ASSERT(m_testCtx->getCommandLine().getRunMode() != RUNMODE_EXECUTE);
212 		return false;
213 	}
214 
215 	// Poll platform events
216 	const bool platformOk = m_platform.processEvents();
217 
218 	// Iterate a step.
219 	bool testExecOk = false;
220 	if (platformOk)
221 	{
222 		try
223 		{
224 			testExecOk = m_testExecutor->iterate();
225 		}
226 		catch (const std::exception& e)
227 		{
228 			die("%s", e.what());
229 		}
230 	}
231 
232 	if ((!platformOk || !testExecOk) )
233 	{
234 		if (!m_testCtx->getCommandLine().isSubProcess())
235 		{
236 			if (!platformOk)
237 				print("\nABORTED!\n");
238 			else
239 				print("\nDONE!\n");
240 		}
241 
242 		const RunMode runMode = m_testCtx->getCommandLine().getRunMode();
243 		if (runMode == RUNMODE_EXECUTE)
244 		{
245 			const TestRunStatus& result = m_testExecutor->getStatus();
246 			if(!m_testCtx->getCommandLine().isSubProcess())
247 			{
248 				// Report statistics.
249 				print("\nTest run totals:\n");
250 				print("  Passed:        %d/%d (%.1f%%)\n", result.numPassed,		result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numPassed			/ (float)result.numExecuted) : 0.0f));
251 				print("  Failed:        %d/%d (%.1f%%)\n", result.numFailed,		result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numFailed			/ (float)result.numExecuted) : 0.0f));
252 				print("  Not supported: %d/%d (%.1f%%)\n", result.numNotSupported,	result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numNotSupported	/ (float)result.numExecuted) : 0.0f));
253 				print("  Warnings:      %d/%d (%.1f%%)\n", result.numWarnings,		result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numWarnings		/ (float)result.numExecuted) : 0.0f));
254 				print("  Waived:        %d/%d (%.1f%%)\n", result.numWaived,		result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numWaived			/ (float)result.numExecuted) : 0.0f));
255 				if (!result.isComplete)
256 					print("Test run was ABORTED!\n");
257 			}
258 			else
259 			{
260 				// subprocess sends test statisticts through qpa file, so that main process may read it
261 				// and add to global statistics ( search for #SubProcessStatus to see how it's done )
262 				std::ostringstream str;
263 				str << "\n#SubProcessStatus " <<
264 					result.numExecuted		<< " " <<
265 					result.numPassed		<< " " <<
266 					result.numFailed		<< " " <<
267 					result.numNotSupported	<< " " <<
268 					result.numWarnings		<< " " <<
269 					result.numWaived		<< "\n";
270 				m_testCtx->getLog().writeRaw(str.str().c_str());
271 			}
272 		}
273 	}
274 
275 	return platformOk && testExecOk;
276 }
277 
getResult(void) const278 const TestRunStatus& App::getResult (void) const
279 {
280 	return m_testExecutor->getStatus();
281 }
282 
onWatchdogTimeout(qpWatchDog * watchDog,void * userPtr,qpTimeoutReason reason)283 void App::onWatchdogTimeout (qpWatchDog* watchDog, void* userPtr, qpTimeoutReason reason)
284 {
285 	DE_UNREF(watchDog);
286 	static_cast<App*>(userPtr)->onWatchdogTimeout(reason);
287 }
288 
onCrash(qpCrashHandler * crashHandler,void * userPtr)289 void App::onCrash (qpCrashHandler* crashHandler, void* userPtr)
290 {
291 	DE_UNREF(crashHandler);
292 	static_cast<App*>(userPtr)->onCrash();
293 }
294 
onWatchdogTimeout(qpTimeoutReason reason)295 void App::onWatchdogTimeout (qpTimeoutReason reason)
296 {
297 	if (!m_crashLock.tryLock() || m_crashed)
298 		return; // In crash handler already.
299 
300 	m_crashed = true;
301 
302 	m_testCtx->getLog().terminateCase(QP_TEST_RESULT_TIMEOUT);
303 	die("Watchdog timer timeout for %s", (reason == QP_TIMEOUT_REASON_INTERVAL_LIMIT ? "touch interval" : "total time"));
304 }
305 
writeCrashToLog(void * userPtr,const char * infoString)306 static void writeCrashToLog (void* userPtr, const char* infoString)
307 {
308 	// \note THIS IS CALLED BY SIGNAL HANDLER! CALLING MALLOC/FREE IS NOT ALLOWED!
309 	TestLog* log = static_cast<TestLog*>(userPtr);
310 	log->writeMessage(infoString);
311 }
312 
writeCrashToConsole(void * userPtr,const char * infoString)313 static void writeCrashToConsole (void* userPtr, const char* infoString)
314 {
315 	// \note THIS IS CALLED BY SIGNAL HANDLER! CALLING MALLOC/FREE IS NOT ALLOWED!
316 	DE_UNREF(userPtr);
317 	qpPrint(infoString);
318 }
319 
onCrash(void)320 void App::onCrash (void)
321 {
322 	// \note THIS IS CALLED BY SIGNAL HANDLER! CALLING MALLOC/FREE IS NOT ALLOWED!
323 
324 	if (!m_crashLock.tryLock() || m_crashed)
325 		return; // In crash handler already.
326 
327 	m_crashed = true;
328 
329 	bool isInCase = m_testExecutor ? m_testExecutor->isInTestCase() : false;
330 
331 	if (isInCase)
332 	{
333 		qpCrashHandler_writeCrashInfo(m_crashHandler, writeCrashToLog, &m_testCtx->getLog());
334 		m_testCtx->getLog().terminateCase(QP_TEST_RESULT_CRASH);
335 	}
336 	else
337 		qpCrashHandler_writeCrashInfo(m_crashHandler, writeCrashToConsole, DE_NULL);
338 
339 	die("Test program crashed");
340 }
341 
342 } // tcu
343