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)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 /*--------------------------------------------------------------------*//*!
75 * Verifies that amber capability requirements in the .amber files
76 * match with capabilities defined on the CTS C code.
77 *//*--------------------------------------------------------------------*/
verifyAmberCapabilityCoherency(TestPackageRoot & root,TestContext & testCtx)78 static void verifyAmberCapabilityCoherency (TestPackageRoot& root, TestContext& testCtx)
79 {
80 DefaultHierarchyInflater inflater(testCtx);
81 de::MovePtr<const CaseListFilter> caseListFilter(testCtx.getCommandLine().createCaseListFilter(testCtx.getArchive()));
82 TestHierarchyIterator iter(root, inflater, *caseListFilter);
83 int count = 0;
84 int errorCount = 0;
85
86 bool ok = true;
87
88 while (iter.getState() != TestHierarchyIterator::STATE_FINISHED)
89 {
90 iter.next();
91
92 while (iter.getNode()->getNodeType() != NODETYPE_PACKAGE)
93 {
94 if (iter.getState() == TestHierarchyIterator::STATE_ENTER_NODE &&
95 isTestNodeTypeExecutable(iter.getNode()->getNodeType()))
96 {
97 std::cout << iter.getNodePath() << "\n";
98 testCtx.getLog() << tcu::TestLog::Message << iter.getNodePath() << tcu::TestLog::EndMessage;
99 if (!iter.getNode()->validateRequirements())
100 {
101 ok = false;
102 errorCount++;
103 }
104 count++;
105 }
106 iter.next();
107 }
108
109 DE_ASSERT(iter.getState() == TestHierarchyIterator::STATE_LEAVE_NODE &&
110 iter.getNode()->getNodeType() == NODETYPE_PACKAGE);
111 iter.next();
112 }
113 std::cout << count << " amber tests, " << errorCount << " errors.\n";
114 if (!ok)
115 TCU_THROW(InternalError, "One or more CTS and Amber test requirements do not match; check log for details");
116
117 }
118
119 /*--------------------------------------------------------------------*//*!
120 * \brief Construct test application
121 *
122 * If a fatal error occurs during initialization constructor will call
123 * die() with debug information.
124 *
125 * \param platform Reference to platform implementation.
126 *//*--------------------------------------------------------------------*/
App(Platform & platform,Archive & archive,TestLog & log,const CommandLine & cmdLine)127 App::App (Platform& platform, Archive& archive, TestLog& log, const CommandLine& cmdLine)
128 : m_platform (platform)
129 , m_watchDog (DE_NULL)
130 , m_crashHandler (DE_NULL)
131 , m_crashed (false)
132 , m_testCtx (DE_NULL)
133 , m_testRoot (DE_NULL)
134 , m_testExecutor (DE_NULL)
135 {
136 if (!cmdLine.isSubProcess())
137 {
138 print("dEQP Core %s (0x%08x) starting..\n", qpGetReleaseName(), qpGetReleaseId());
139 print(" target implementation = '%s'\n", qpGetTargetName());
140 }
141
142 if (!deSetRoundingMode(DE_ROUNDINGMODE_TO_NEAREST_EVEN))
143 qpPrintf("WARNING: Failed to set floating-point rounding mode!\n");
144
145 try
146 {
147 const RunMode runMode = cmdLine.getRunMode();
148
149 // Initialize watchdog
150 if (cmdLine.isWatchDogEnabled())
151 TCU_CHECK_INTERNAL(m_watchDog = qpWatchDog_create(onWatchdogTimeout, this, WATCHDOG_TOTAL_TIME_LIMIT_SECS, WATCHDOG_INTERVAL_TIME_LIMIT_SECS));
152
153 // Initialize crash handler.
154 if (cmdLine.isCrashHandlingEnabled())
155 TCU_CHECK_INTERNAL(m_crashHandler = qpCrashHandler_create(onCrash, this));
156
157 // Create test context
158 m_testCtx = new TestContext(m_platform, archive, log, cmdLine, m_watchDog);
159
160 // Create root from registry
161 m_testRoot = new TestPackageRoot(*m_testCtx, TestPackageRegistry::getSingleton());
162
163 // \note No executor is created if runmode is not EXECUTE
164 if (runMode == RUNMODE_EXECUTE)
165 m_testExecutor = new TestSessionExecutor(*m_testRoot, *m_testCtx);
166 else if (runMode == RUNMODE_DUMP_STDOUT_CASELIST)
167 writeCaselistsToStdout(*m_testRoot, *m_testCtx);
168 else if (runMode == RUNMODE_DUMP_XML_CASELIST)
169 writeXmlCaselistsToFiles(*m_testRoot, *m_testCtx, cmdLine);
170 else if (runMode == RUNMODE_DUMP_TEXT_CASELIST)
171 writeTxtCaselistsToFiles(*m_testRoot, *m_testCtx, cmdLine);
172 else if (runMode == RUNMODE_VERIFY_AMBER_COHERENCY)
173 verifyAmberCapabilityCoherency(*m_testRoot, *m_testCtx);
174 else
175 DE_ASSERT(false);
176 }
177 catch (const std::exception& e)
178 {
179 cleanup();
180 die("Failed to initialize dEQP: %s", e.what());
181 }
182 }
183
~App(void)184 App::~App (void)
185 {
186 cleanup();
187 }
188
cleanup(void)189 void App::cleanup (void)
190 {
191 delete m_testExecutor;
192 delete m_testRoot;
193 delete m_testCtx;
194
195 if (m_crashHandler)
196 qpCrashHandler_destroy(m_crashHandler);
197
198 if (m_watchDog)
199 qpWatchDog_destroy(m_watchDog);
200 }
201
202 /*--------------------------------------------------------------------*//*!
203 * \brief Step forward test execution
204 * \return true if application should call iterate() again and false
205 * if test execution session is complete.
206 *//*--------------------------------------------------------------------*/
iterate(void)207 bool App::iterate (void)
208 {
209 if (!m_testExecutor)
210 {
211 DE_ASSERT(m_testCtx->getCommandLine().getRunMode() != RUNMODE_EXECUTE);
212 return false;
213 }
214
215 // Poll platform events
216 const bool platformOk = m_platform.processEvents();
217
218 // Iterate a step.
219 bool testExecOk = false;
220 if (platformOk)
221 {
222 try
223 {
224 testExecOk = m_testExecutor->iterate();
225 }
226 catch (const std::exception& e)
227 {
228 die("%s", e.what());
229 }
230 }
231
232 if ((!platformOk || !testExecOk) )
233 {
234 if (!m_testCtx->getCommandLine().isSubProcess())
235 {
236 if (!platformOk)
237 print("\nABORTED!\n");
238 else
239 print("\nDONE!\n");
240 }
241
242 const RunMode runMode = m_testCtx->getCommandLine().getRunMode();
243 if (runMode == RUNMODE_EXECUTE)
244 {
245 const TestRunStatus& result = m_testExecutor->getStatus();
246 if(!m_testCtx->getCommandLine().isSubProcess())
247 {
248 // Report statistics.
249 print("\nTest run totals:\n");
250 print(" Passed: %d/%d (%.1f%%)\n", result.numPassed, result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numPassed / (float)result.numExecuted) : 0.0f));
251 print(" Failed: %d/%d (%.1f%%)\n", result.numFailed, result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numFailed / (float)result.numExecuted) : 0.0f));
252 print(" Not supported: %d/%d (%.1f%%)\n", result.numNotSupported, result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numNotSupported / (float)result.numExecuted) : 0.0f));
253 print(" Warnings: %d/%d (%.1f%%)\n", result.numWarnings, result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numWarnings / (float)result.numExecuted) : 0.0f));
254 print(" Waived: %d/%d (%.1f%%)\n", result.numWaived, result.numExecuted, (result.numExecuted > 0 ? (100.0f * (float)result.numWaived / (float)result.numExecuted) : 0.0f));
255 if (!result.isComplete)
256 print("Test run was ABORTED!\n");
257 }
258 else
259 {
260 // subprocess sends test statisticts through qpa file, so that main process may read it
261 // and add to global statistics ( search for #SubProcessStatus to see how it's done )
262 std::ostringstream str;
263 str << "\n#SubProcessStatus " <<
264 result.numExecuted << " " <<
265 result.numPassed << " " <<
266 result.numFailed << " " <<
267 result.numNotSupported << " " <<
268 result.numWarnings << " " <<
269 result.numWaived << "\n";
270 m_testCtx->getLog().writeRaw(str.str().c_str());
271 }
272 }
273 }
274
275 return platformOk && testExecOk;
276 }
277
getResult(void) const278 const TestRunStatus& App::getResult (void) const
279 {
280 return m_testExecutor->getStatus();
281 }
282
onWatchdogTimeout(qpWatchDog * watchDog,void * userPtr,qpTimeoutReason reason)283 void App::onWatchdogTimeout (qpWatchDog* watchDog, void* userPtr, qpTimeoutReason reason)
284 {
285 DE_UNREF(watchDog);
286 static_cast<App*>(userPtr)->onWatchdogTimeout(reason);
287 }
288
onCrash(qpCrashHandler * crashHandler,void * userPtr)289 void App::onCrash (qpCrashHandler* crashHandler, void* userPtr)
290 {
291 DE_UNREF(crashHandler);
292 static_cast<App*>(userPtr)->onCrash();
293 }
294
onWatchdogTimeout(qpTimeoutReason reason)295 void App::onWatchdogTimeout (qpTimeoutReason reason)
296 {
297 if (!m_crashLock.tryLock() || m_crashed)
298 return; // In crash handler already.
299
300 m_crashed = true;
301
302 m_testCtx->getLog().terminateCase(QP_TEST_RESULT_TIMEOUT);
303 die("Watchdog timer timeout for %s", (reason == QP_TIMEOUT_REASON_INTERVAL_LIMIT ? "touch interval" : "total time"));
304 }
305
writeCrashToLog(void * userPtr,const char * infoString)306 static void writeCrashToLog (void* userPtr, const char* infoString)
307 {
308 // \note THIS IS CALLED BY SIGNAL HANDLER! CALLING MALLOC/FREE IS NOT ALLOWED!
309 TestLog* log = static_cast<TestLog*>(userPtr);
310 log->writeMessage(infoString);
311 }
312
writeCrashToConsole(void * userPtr,const char * infoString)313 static void writeCrashToConsole (void* userPtr, const char* infoString)
314 {
315 // \note THIS IS CALLED BY SIGNAL HANDLER! CALLING MALLOC/FREE IS NOT ALLOWED!
316 DE_UNREF(userPtr);
317 qpPrint(infoString);
318 }
319
onCrash(void)320 void App::onCrash (void)
321 {
322 // \note THIS IS CALLED BY SIGNAL HANDLER! CALLING MALLOC/FREE IS NOT ALLOWED!
323
324 if (!m_crashLock.tryLock() || m_crashed)
325 return; // In crash handler already.
326
327 m_crashed = true;
328
329 bool isInCase = m_testExecutor ? m_testExecutor->isInTestCase() : false;
330
331 if (isInCase)
332 {
333 qpCrashHandler_writeCrashInfo(m_crashHandler, writeCrashToLog, &m_testCtx->getLog());
334 m_testCtx->getLog().terminateCase(QP_TEST_RESULT_CRASH);
335 }
336 else
337 qpCrashHandler_writeCrashInfo(m_crashHandler, writeCrashToConsole, DE_NULL);
338
339 die("Test program crashed");
340 }
341
342 } // tcu
343