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,const CommandLine & cmdLine)50 static 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 *//*--------------------------------------------------------------------*/
App(Platform & platform,Archive & archive,TestLog & log,const CommandLine & cmdLine)80 App::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_EVEN))
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
~App(void)132 App::~App (void)
133 {
134 cleanup();
135 }
136
cleanup(void)137 void 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 *//*--------------------------------------------------------------------*/
iterate(void)155 bool 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
onWatchdogTimeout(qpWatchDog * watchDog,void * userPtr,qpTimeoutReason reason)206 void App::onWatchdogTimeout (qpWatchDog* watchDog, void* userPtr, qpTimeoutReason reason)
207 {
208 DE_UNREF(watchDog);
209 static_cast<App*>(userPtr)->onWatchdogTimeout(reason);
210 }
211
onCrash(qpCrashHandler * crashHandler,void * userPtr)212 void App::onCrash (qpCrashHandler* crashHandler, void* userPtr)
213 {
214 DE_UNREF(crashHandler);
215 static_cast<App*>(userPtr)->onCrash();
216 }
217
onWatchdogTimeout(qpTimeoutReason reason)218 void App::onWatchdogTimeout (qpTimeoutReason reason)
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 for %s", (reason == QP_TIMEOUT_REASON_INTERVAL_LIMIT ? "touch interval" : "total time"));
227 }
228
writeCrashToLog(void * userPtr,const char * infoString)229 static 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
writeCrashToConsole(void * userPtr,const char * infoString)236 static 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
onCrash(void)243 void 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