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 #include "qpInfo.h"
32 #include "qpDebugOut.h"
33 #include "deMath.h"
34
35 namespace tcu
36 {
37
38 /*--------------------------------------------------------------------*//*!
39 * \brief Construct test application
40 *
41 * If a fatal error occurs during initialization constructor will call
42 * die() with debug information.
43 *
44 * \param platform Reference to platform implementation.
45 *//*--------------------------------------------------------------------*/
App(Platform & platform,Archive & archive,TestLog & log,const CommandLine & cmdLine)46 App::App (Platform& platform, Archive& archive, TestLog& log, const CommandLine& cmdLine)
47 : m_platform (platform)
48 , m_watchDog (DE_NULL)
49 , m_crashHandler (DE_NULL)
50 , m_crashed (false)
51 , m_testCtx (DE_NULL)
52 , m_testRoot (DE_NULL)
53 , m_testExecutor (DE_NULL)
54 {
55 print("dEQP Core %s (0x%08x) starting..\n", qpGetReleaseName(), qpGetReleaseId());
56 print(" target implementation = '%s'\n", qpGetTargetName());
57
58 if (!deSetRoundingMode(DE_ROUNDINGMODE_TO_NEAREST))
59 qpPrintf("WARNING: Failed to set floating-point rounding mode!\n");
60
61 try
62 {
63 const RunMode runMode = cmdLine.getRunMode();
64
65 // Initialize watchdog
66 if (cmdLine.isWatchDogEnabled())
67 TCU_CHECK_INTERNAL(m_watchDog = qpWatchDog_create(onWatchdogTimeout, this, 300, 30));
68
69 // Initialize crash handler.
70 if (cmdLine.isCrashHandlingEnabled())
71 TCU_CHECK_INTERNAL(m_crashHandler = qpCrashHandler_create(onCrash, this));
72
73 // Create test context
74 m_testCtx = new TestContext(m_platform, archive, log, cmdLine, m_watchDog);
75
76 // Create root from registry
77 m_testRoot = new TestPackageRoot(*m_testCtx, TestPackageRegistry::getSingleton());
78
79 // \note No executor is created if runmode is not EXECUTE
80 if (runMode == RUNMODE_EXECUTE)
81 m_testExecutor = new TestSessionExecutor(*m_testRoot, *m_testCtx);
82 else if (runMode == RUNMODE_DUMP_XML_CASELIST)
83 writeXmlCaselists(*m_testRoot, *m_testCtx, m_testCtx->getCommandLine());
84 else if (runMode == RUNMODE_DUMP_TEXT_CASELIST)
85 writeTxtCaselists(*m_testRoot, *m_testCtx, m_testCtx->getCommandLine());
86 else
87 DE_ASSERT(false);
88 }
89 catch (const std::exception& e)
90 {
91 cleanup();
92 die("Failed to initialize dEQP: %s", e.what());
93 }
94 }
95
~App(void)96 App::~App (void)
97 {
98 cleanup();
99 }
100
cleanup(void)101 void App::cleanup (void)
102 {
103 delete m_testExecutor;
104 delete m_testRoot;
105 delete m_testCtx;
106
107 if (m_crashHandler)
108 qpCrashHandler_destroy(m_crashHandler);
109
110 if (m_watchDog)
111 qpWatchDog_destroy(m_watchDog);
112 }
113
114 /*--------------------------------------------------------------------*//*!
115 * \brief Step forward test execution
116 * \return true if application should call iterate() again and false
117 * if test execution session is complete.
118 *//*--------------------------------------------------------------------*/
iterate(void)119 bool App::iterate (void)
120 {
121 if (!m_testExecutor)
122 {
123 DE_ASSERT(m_testCtx->getCommandLine().getRunMode() != RUNMODE_EXECUTE);
124 return false;
125 }
126
127 // Poll platform events
128 const bool platformOk = m_platform.processEvents();
129
130 // Iterate a step.
131 bool testExecOk = false;
132 if (platformOk)
133 {
134 try
135 {
136 testExecOk = m_testExecutor->iterate();
137 }
138 catch (const std::exception& e)
139 {
140 die("%s", e.what());
141 }
142 }
143
144 if (!platformOk || !testExecOk)
145 {
146 if (!platformOk)
147 print("\nABORTED!\n");
148 else
149 print("\nDONE!\n");
150
151 const RunMode runMode = m_testCtx->getCommandLine().getRunMode();
152 if (runMode == RUNMODE_EXECUTE)
153 {
154 const TestRunStatus& result = m_testExecutor->getStatus();
155
156 // Report statistics.
157 print("\nTest run totals:\n");
158 print(" Passed: %d/%d (%.1f%%)\n", result.numPassed, result.numExecuted, (result.numExecuted > 0 ? (100.0f * result.numPassed / result.numExecuted) : 0.0f));
159 print(" Failed: %d/%d (%.1f%%)\n", result.numFailed, result.numExecuted, (result.numExecuted > 0 ? (100.0f * result.numFailed / result.numExecuted) : 0.0f));
160 print(" Not supported: %d/%d (%.1f%%)\n", result.numNotSupported, result.numExecuted, (result.numExecuted > 0 ? (100.0f * result.numNotSupported / result.numExecuted) : 0.0f));
161 print(" Warnings: %d/%d (%.1f%%)\n", result.numWarnings, result.numExecuted, (result.numExecuted > 0 ? (100.0f * result.numWarnings / result.numExecuted) : 0.0f));
162 if (!result.isComplete)
163 print("Test run was ABORTED!\n");
164 }
165 }
166
167 return platformOk && testExecOk;
168 }
169
onWatchdogTimeout(qpWatchDog * watchDog,void * userPtr)170 void App::onWatchdogTimeout (qpWatchDog* watchDog, void* userPtr)
171 {
172 DE_UNREF(watchDog);
173 static_cast<App*>(userPtr)->onWatchdogTimeout();
174 }
175
onCrash(qpCrashHandler * crashHandler,void * userPtr)176 void App::onCrash (qpCrashHandler* crashHandler, void* userPtr)
177 {
178 DE_UNREF(crashHandler);
179 static_cast<App*>(userPtr)->onCrash();
180 }
181
onWatchdogTimeout(void)182 void App::onWatchdogTimeout (void)
183 {
184 if (!m_crashLock.tryLock() || m_crashed)
185 return; // In crash handler already.
186
187 m_crashed = true;
188
189 m_testCtx->getLog().terminateCase(QP_TEST_RESULT_TIMEOUT);
190 die("Watchdog timer timeout");
191 }
192
writeCrashToLog(void * userPtr,const char * infoString)193 static void writeCrashToLog (void* userPtr, const char* infoString)
194 {
195 // \note THIS IS CALLED BY SIGNAL HANDLER! CALLING MALLOC/FREE IS NOT ALLOWED!
196 TestLog* log = static_cast<TestLog*>(userPtr);
197 log->writeMessage(infoString);
198 }
199
writeCrashToConsole(void * userPtr,const char * infoString)200 static void writeCrashToConsole (void* userPtr, const char* infoString)
201 {
202 // \note THIS IS CALLED BY SIGNAL HANDLER! CALLING MALLOC/FREE IS NOT ALLOWED!
203 DE_UNREF(userPtr);
204 qpPrint(infoString);
205 }
206
onCrash(void)207 void App::onCrash (void)
208 {
209 // \note THIS IS CALLED BY SIGNAL HANDLER! CALLING MALLOC/FREE IS NOT ALLOWED!
210
211 if (!m_crashLock.tryLock() || m_crashed)
212 return; // In crash handler already.
213
214 m_crashed = true;
215
216 bool isInCase = m_testExecutor ? m_testExecutor->isInTestCase() : false;
217
218 if (isInCase)
219 {
220 qpCrashHandler_writeCrashInfo(m_crashHandler, writeCrashToLog, &m_testCtx->getLog());
221 m_testCtx->getLog().terminateCase(QP_TEST_RESULT_CRASH);
222 }
223 else
224 qpCrashHandler_writeCrashInfo(m_crashHandler, writeCrashToConsole, DE_NULL);
225
226 die("Test program crashed");
227 }
228
229 } // tcu
230