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