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 39namespace tcu 40{ 41 42using 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 *//*--------------------------------------------------------------------*/ 50static 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 *//*--------------------------------------------------------------------*/ 80App::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 132App::~App (void) 133{ 134 cleanup(); 135} 136 137void 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 *//*--------------------------------------------------------------------*/ 155bool 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 206void App::onWatchdogTimeout (qpWatchDog* watchDog, void* userPtr) 207{ 208 DE_UNREF(watchDog); 209 static_cast<App*>(userPtr)->onWatchdogTimeout(); 210} 211 212void App::onCrash (qpCrashHandler* crashHandler, void* userPtr) 213{ 214 DE_UNREF(crashHandler); 215 static_cast<App*>(userPtr)->onCrash(); 216} 217 218void 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 229static 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 236static 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 243void 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