Home | History | Annotate | Download | only in common
      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  *//*--------------------------------------------------------------------*/
     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  * \brief Construct test application
     75  *
     76  * If a fatal error occurs during initialization constructor will call
     77  * die() with debug information.
     78  *
     79  * \param platform Reference to platform implementation.
     80  *//*--------------------------------------------------------------------*/
     81 App::App (Platform& platform, Archive& archive, TestLog& log, const CommandLine& cmdLine)
     82 	: m_platform		(platform)
     83 	, m_watchDog		(DE_NULL)
     84 	, m_crashHandler	(DE_NULL)
     85 	, m_crashed			(false)
     86 	, m_testCtx			(DE_NULL)
     87 	, m_testRoot		(DE_NULL)
     88 	, m_testExecutor	(DE_NULL)
     89 {
     90 	print("dEQP Core %s (0x%08x) starting..\n", qpGetReleaseName(), qpGetReleaseId());
     91 	print("  target implementation = '%s'\n", qpGetTargetName());
     92 
     93 	if (!deSetRoundingMode(DE_ROUNDINGMODE_TO_NEAREST_EVEN))
     94 		qpPrintf("WARNING: Failed to set floating-point rounding mode!\n");
     95 
     96 	try
     97 	{
     98 		const RunMode	runMode	= cmdLine.getRunMode();
     99 
    100 		// Initialize watchdog
    101 		if (cmdLine.isWatchDogEnabled())
    102 			TCU_CHECK_INTERNAL(m_watchDog = qpWatchDog_create(onWatchdogTimeout, this, WATCHDOG_TOTAL_TIME_LIMIT_SECS, WATCHDOG_INTERVAL_TIME_LIMIT_SECS));
    103 
    104 		// Initialize crash handler.
    105 		if (cmdLine.isCrashHandlingEnabled())
    106 			TCU_CHECK_INTERNAL(m_crashHandler = qpCrashHandler_create(onCrash, this));
    107 
    108 		// Create test context
    109 		m_testCtx = new TestContext(m_platform, archive, log, cmdLine, m_watchDog);
    110 
    111 		// Create root from registry
    112 		m_testRoot = new TestPackageRoot(*m_testCtx, TestPackageRegistry::getSingleton());
    113 
    114 		// \note No executor is created if runmode is not EXECUTE
    115 		if (runMode == RUNMODE_EXECUTE)
    116 			m_testExecutor = new TestSessionExecutor(*m_testRoot, *m_testCtx);
    117 		else if (runMode == RUNMODE_DUMP_STDOUT_CASELIST)
    118 			writeCaselistsToStdout(*m_testRoot, *m_testCtx);
    119 		else if (runMode == RUNMODE_DUMP_XML_CASELIST)
    120 			writeXmlCaselistsToFiles(*m_testRoot, *m_testCtx, cmdLine);
    121 		else if (runMode == RUNMODE_DUMP_TEXT_CASELIST)
    122 			writeTxtCaselistsToFiles(*m_testRoot, *m_testCtx, cmdLine);
    123 		else
    124 			DE_ASSERT(false);
    125 	}
    126 	catch (const std::exception& e)
    127 	{
    128 		cleanup();
    129 		die("Failed to initialize dEQP: %s", e.what());
    130 	}
    131 }
    132 
    133 App::~App (void)
    134 {
    135 	cleanup();
    136 }
    137 
    138 void App::cleanup (void)
    139 {
    140 	delete m_testExecutor;
    141 	delete m_testRoot;
    142 	delete m_testCtx;
    143 
    144 	if (m_crashHandler)
    145 		qpCrashHandler_destroy(m_crashHandler);
    146 
    147 	if (m_watchDog)
    148 		qpWatchDog_destroy(m_watchDog);
    149 }
    150 
    151 /*--------------------------------------------------------------------*//*!
    152  * \brief Step forward test execution
    153  * \return true if application should call iterate() again and false
    154  *         if test execution session is complete.
    155  *//*--------------------------------------------------------------------*/
    156 bool App::iterate (void)
    157 {
    158 	if (!m_testExecutor)
    159 	{
    160 		DE_ASSERT(m_testCtx->getCommandLine().getRunMode() != RUNMODE_EXECUTE);
    161 		return false;
    162 	}
    163 
    164 	// Poll platform events
    165 	const bool platformOk = m_platform.processEvents();
    166 
    167 	// Iterate a step.
    168 	bool testExecOk = false;
    169 	if (platformOk)
    170 	{
    171 		try
    172 		{
    173 			testExecOk = m_testExecutor->iterate();
    174 		}
    175 		catch (const std::exception& e)
    176 		{
    177 			die("%s", e.what());
    178 		}
    179 	}
    180 
    181 	if (!platformOk || !testExecOk)
    182 	{
    183 		if (!platformOk)
    184 			print("\nABORTED!\n");
    185 		else
    186 			print("\nDONE!\n");
    187 
    188 		const RunMode runMode = m_testCtx->getCommandLine().getRunMode();
    189 		if (runMode == RUNMODE_EXECUTE)
    190 		{
    191 			const TestRunStatus& result = m_testExecutor->getStatus();
    192 
    193 			// Report statistics.
    194 			print("\nTest run totals:\n");
    195 			print("  Passed:        %d/%d (%.1f%%)\n", result.numPassed,		result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numPassed			/ (float)result.numExecuted) : 0.0f));
    196 			print("  Failed:        %d/%d (%.1f%%)\n", result.numFailed,		result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numFailed			/ (float)result.numExecuted) : 0.0f));
    197 			print("  Not supported: %d/%d (%.1f%%)\n", result.numNotSupported,	result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numNotSupported	/ (float)result.numExecuted) : 0.0f));
    198 			print("  Warnings:      %d/%d (%.1f%%)\n", result.numWarnings,		result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numWarnings		/ (float)result.numExecuted) : 0.0f));
    199 			if (!result.isComplete)
    200 				print("Test run was ABORTED!\n");
    201 		}
    202 	}
    203 
    204 	return platformOk && testExecOk;
    205 }
    206 
    207 const TestRunStatus& App::getResult (void) const
    208 {
    209 	return m_testExecutor->getStatus();
    210 }
    211 
    212 void App::onWatchdogTimeout (qpWatchDog* watchDog, void* userPtr, qpTimeoutReason reason)
    213 {
    214 	DE_UNREF(watchDog);
    215 	static_cast<App*>(userPtr)->onWatchdogTimeout(reason);
    216 }
    217 
    218 void App::onCrash (qpCrashHandler* crashHandler, void* userPtr)
    219 {
    220 	DE_UNREF(crashHandler);
    221 	static_cast<App*>(userPtr)->onCrash();
    222 }
    223 
    224 void App::onWatchdogTimeout (qpTimeoutReason reason)
    225 {
    226 	if (!m_crashLock.tryLock() || m_crashed)
    227 		return; // In crash handler already.
    228 
    229 	m_crashed = true;
    230 
    231 	m_testCtx->getLog().terminateCase(QP_TEST_RESULT_TIMEOUT);
    232 	die("Watchdog timer timeout for %s", (reason == QP_TIMEOUT_REASON_INTERVAL_LIMIT ? "touch interval" : "total time"));
    233 }
    234 
    235 static void writeCrashToLog (void* userPtr, const char* infoString)
    236 {
    237 	// \note THIS IS CALLED BY SIGNAL HANDLER! CALLING MALLOC/FREE IS NOT ALLOWED!
    238 	TestLog* log = static_cast<TestLog*>(userPtr);
    239 	log->writeMessage(infoString);
    240 }
    241 
    242 static void writeCrashToConsole (void* userPtr, const char* infoString)
    243 {
    244 	// \note THIS IS CALLED BY SIGNAL HANDLER! CALLING MALLOC/FREE IS NOT ALLOWED!
    245 	DE_UNREF(userPtr);
    246 	qpPrint(infoString);
    247 }
    248 
    249 void App::onCrash (void)
    250 {
    251 	// \note THIS IS CALLED BY SIGNAL HANDLER! CALLING MALLOC/FREE IS NOT ALLOWED!
    252 
    253 	if (!m_crashLock.tryLock() || m_crashed)
    254 		return; // In crash handler already.
    255 
    256 	m_crashed = true;
    257 
    258 	bool isInCase = m_testExecutor ? m_testExecutor->isInTestCase() : false;
    259 
    260 	if (isInCase)
    261 	{
    262 		qpCrashHandler_writeCrashInfo(m_crashHandler, writeCrashToLog, &m_testCtx->getLog());
    263 		m_testCtx->getLog().terminateCase(QP_TEST_RESULT_CRASH);
    264 	}
    265 	else
    266 		qpCrashHandler_writeCrashInfo(m_crashHandler, writeCrashToConsole, DE_NULL);
    267 
    268 	die("Test program crashed");
    269 }
    270 
    271 } // tcu
    272