am 9252e819: Remove tessellation.user_defined_io.per_patch cases from must pass.
[platform/upstream/VK-GL-CTS.git] / executor / xeBatchExecutor.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Test Executor
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 Test batch executor.
22  *//*--------------------------------------------------------------------*/
23
24 #include "xeBatchExecutor.hpp"
25 #include "xeTestResultParser.hpp"
26
27 #include <sstream>
28 #include <cstdio>
29
30 namespace xe
31 {
32
33 using std::string;
34 using std::vector;
35
36 enum
37 {
38         TEST_LOG_TMP_BUFFER_SIZE        = 1024,
39         INFO_LOG_TMP_BUFFER_SIZE        = 256
40 };
41
42 // \todo [2012-11-01 pyry] Update execute set in handler.
43
44 static inline bool isExecutedInBatch (const BatchResult* batchResult, const TestCase* testCase)
45 {
46         std::string fullPath;
47         testCase->getFullPath(fullPath);
48
49         if (batchResult->hasTestCaseResult(fullPath.c_str()))
50         {
51                 ConstTestCaseResultPtr data = batchResult->getTestCaseResult(fullPath.c_str());
52                 return data->getStatusCode() != TESTSTATUSCODE_PENDING && data->getStatusCode() != TESTSTATUSCODE_RUNNING;
53         }
54         else
55                 return false;
56 }
57
58 // \todo [2012-06-19 pyry] These can be optimized using TestSetIterator (once implemented)
59
60 static void computeExecuteSet (TestSet& executeSet, const TestNode* root, const TestSet& testSet, const BatchResult* batchResult)
61 {
62         ConstTestNodeIterator   iter    = ConstTestNodeIterator::begin(root);
63         ConstTestNodeIterator   end             = ConstTestNodeIterator::end(root);
64
65         for (; iter != end; ++iter)
66         {
67                 const TestNode* node = *iter;
68
69                 if (node->getNodeType() == TESTNODETYPE_TEST_CASE && testSet.hasNode(node))
70                 {
71                         const TestCase* testCase = static_cast<const TestCase*>(node);
72
73                         if (!isExecutedInBatch(batchResult, testCase))
74                                 executeSet.addCase(testCase);
75                 }
76         }
77 }
78
79 static void computeBatchRequest (TestSet& requestSet, const TestSet& executeSet, const TestNode* root, int maxCasesInSet)
80 {
81         ConstTestNodeIterator   iter            = ConstTestNodeIterator::begin(root);
82         ConstTestNodeIterator   end                     = ConstTestNodeIterator::end(root);
83         int                                             numCases        = 0;
84
85         for (; (iter != end) && (numCases < maxCasesInSet); ++iter)
86         {
87                 const TestNode* node = *iter;
88
89                 if (node->getNodeType() == TESTNODETYPE_TEST_CASE && executeSet.hasNode(node))
90                 {
91                         const TestCase* testCase = static_cast<const TestCase*>(node);
92                         requestSet.addCase(testCase);
93                         numCases += 1;
94                 }
95         }
96 }
97
98 static int removeExecuted (TestSet& set, const TestNode* root, const BatchResult* batchResult)
99 {
100         TestSet                                 oldSet          (set);
101         ConstTestNodeIterator   iter            = ConstTestNodeIterator::begin(root);
102         ConstTestNodeIterator   end                     = ConstTestNodeIterator::end(root);
103         int                                             numRemoved      = 0;
104
105         for (; iter != end; ++iter)
106         {
107                 const TestNode* node = *iter;
108
109                 if (node->getNodeType() == TESTNODETYPE_TEST_CASE && oldSet.hasNode(node))
110                 {
111                         const TestCase* testCase = static_cast<const TestCase*>(node);
112
113                         if (isExecutedInBatch(batchResult, testCase))
114                         {
115                                 set.removeCase(testCase);
116                                 numRemoved += 1;
117                         }
118                 }
119         }
120
121         return numRemoved;
122 }
123
124 BatchExecutorLogHandler::BatchExecutorLogHandler (BatchResult* batchResult)
125         : m_batchResult(batchResult)
126 {
127 }
128
129 BatchExecutorLogHandler::~BatchExecutorLogHandler (void)
130 {
131 }
132
133 void BatchExecutorLogHandler::setSessionInfo (const SessionInfo& sessionInfo)
134 {
135         m_batchResult->getSessionInfo() = sessionInfo;
136 }
137
138 TestCaseResultPtr BatchExecutorLogHandler::startTestCaseResult (const char* casePath)
139 {
140         // \todo [2012-11-01 pyry] What to do with duplicate results?
141         if (m_batchResult->hasTestCaseResult(casePath))
142                 return m_batchResult->getTestCaseResult(casePath);
143         else
144                 return m_batchResult->createTestCaseResult(casePath);
145 }
146
147 void BatchExecutorLogHandler::testCaseResultUpdated (const TestCaseResultPtr&)
148 {
149 }
150
151 void BatchExecutorLogHandler::testCaseResultComplete (const TestCaseResultPtr& result)
152 {
153         // \todo [2012-11-01 pyry] Remove from execute set here instead of updating it between sessions.
154         printf("%s\n", result->getTestCasePath());
155 }
156
157 BatchExecutor::BatchExecutor (const TargetConfiguration& config, CommLink* commLink, const TestNode* root, const TestSet& testSet, BatchResult* batchResult, InfoLog* infoLog)
158         : m_config                      (config)
159         , m_commLink            (commLink)
160         , m_root                        (root)
161         , m_testSet                     (testSet)
162         , m_logHandler          (batchResult)
163         , m_batchResult         (batchResult)
164         , m_infoLog                     (infoLog)
165         , m_state                       (STATE_NOT_STARTED)
166         , m_testLogParser       (&m_logHandler)
167 {
168 }
169
170 BatchExecutor::~BatchExecutor (void)
171 {
172 }
173
174 void BatchExecutor::run (void)
175 {
176         XE_CHECK(m_state == STATE_NOT_STARTED);
177
178         // Check commlink state.
179         {
180                 CommLinkState   commState       = COMMLINKSTATE_LAST;
181                 std::string             stateStr        = "";
182
183                 commState = m_commLink->getState(stateStr);
184
185                 if (commState == COMMLINKSTATE_ERROR)
186                 {
187                         // Report error.
188                         XE_FAIL((string("CommLink error: '") + stateStr + "'").c_str());
189                 }
190                 else if (commState != COMMLINKSTATE_READY)
191                         XE_FAIL("CommLink is not ready");
192         }
193
194         // Compute initial execute set.
195         computeExecuteSet(m_casesToExecute, m_root, m_testSet, m_batchResult);
196
197         // Register callbacks.
198         m_commLink->setCallbacks(enqueueStateChanged, enqueueTestLogData, enqueueInfoLogData, this);
199
200         try
201         {
202                 if (!m_casesToExecute.empty())
203                 {
204                         TestSet batchRequest;
205                         computeBatchRequest(batchRequest, m_casesToExecute, m_root, m_config.maxCasesPerSession);
206                         launchTestSet(batchRequest);
207
208                         m_state = STATE_STARTED;
209                 }
210                 else
211                         m_state = STATE_FINISHED;
212
213                 // Run handler loop until we are finished.
214                 while (m_state != STATE_FINISHED)
215                         m_dispatcher.callNext();
216         }
217         catch (...)
218         {
219                 m_commLink->setCallbacks(DE_NULL, DE_NULL, DE_NULL, DE_NULL);
220                 throw;
221         }
222
223         // De-register callbacks.
224         m_commLink->setCallbacks(DE_NULL, DE_NULL, DE_NULL, DE_NULL);
225 }
226
227 void BatchExecutor::onStateChanged (CommLinkState state, const char* message)
228 {
229         switch (state)
230         {
231                 case COMMLINKSTATE_READY:
232                 case COMMLINKSTATE_TEST_PROCESS_LAUNCHING:
233                 case COMMLINKSTATE_TEST_PROCESS_RUNNING:
234                         break; // Ignore.
235
236                 case COMMLINKSTATE_TEST_PROCESS_FINISHED:
237                 {
238                         // Feed end of string to parser. This terminates open test case if such exists.
239                         {
240                                 deUint8 eos = 0;
241                                 onTestLogData(&eos, 1);
242                         }
243
244                         int numExecuted = removeExecuted(m_casesToExecute, m_root, m_batchResult);
245
246                         // \note No new batch is launched if no cases were executed in last one. Otherwise excutor
247                         //       could end up in infinite loop.
248                         if (!m_casesToExecute.empty() && numExecuted > 0)
249                         {
250                                 // Reset state and start batch.
251                                 m_testLogParser.reset();
252
253                                 m_commLink->reset();
254                                 XE_CHECK(m_commLink->getState() == COMMLINKSTATE_READY);
255
256                                 TestSet batchRequest;
257                                 computeBatchRequest(batchRequest, m_casesToExecute, m_root, m_config.maxCasesPerSession);
258                                 launchTestSet(batchRequest);
259                         }
260                         else
261                                 m_state = STATE_FINISHED;
262
263                         break;
264                 }
265
266                 case COMMLINKSTATE_TEST_PROCESS_LAUNCH_FAILED:
267                         printf("Failed to start test process: '%s'\n", message);
268                         m_state = STATE_FINISHED;
269                         break;
270
271                 case COMMLINKSTATE_ERROR:
272                         printf("CommLink error: '%s'\n", message);
273                         m_state = STATE_FINISHED;
274                         break;
275
276                 default:
277                         XE_FAIL("Unknown state");
278         }
279 }
280
281 void BatchExecutor::onTestLogData (const deUint8* bytes, int numBytes)
282 {
283         try
284         {
285                 m_testLogParser.parse(bytes, numBytes);
286         }
287         catch (const ParseError& e)
288         {
289                 // \todo [2012-07-06 pyry] Log error.
290                 DE_UNREF(e);
291         }
292 }
293
294 void BatchExecutor::onInfoLogData (const deUint8* bytes, int numBytes)
295 {
296         if (numBytes > 0 && m_infoLog)
297                 m_infoLog->append(bytes, numBytes);
298 }
299
300 static void writeCaseListNode (std::ostream& str, const TestNode* node, const TestSet& testSet)
301 {
302         DE_ASSERT(testSet.hasNode(node));
303
304         TestNodeType nodeType = node->getNodeType();
305
306         if (nodeType != TESTNODETYPE_ROOT)
307                 str << node->getName();
308
309         if (nodeType == TESTNODETYPE_ROOT || nodeType == TESTNODETYPE_GROUP)
310         {
311                 const TestGroup*        group   = static_cast<const TestGroup*>(node);
312                 bool                            isFirst = true;
313
314                 str << "{";
315
316                 for (int ndx = 0; ndx < group->getNumChildren(); ndx++)
317                 {
318                         const TestNode* child = group->getChild(ndx);
319
320                         if (testSet.hasNode(child))
321                         {
322                                 if (!isFirst)
323                                         str << ",";
324
325                                 writeCaseListNode(str, child, testSet);
326                                 isFirst = false;
327                         }
328                 }
329
330                 str << "}";
331         }
332 }
333
334 void BatchExecutor::launchTestSet (const TestSet& testSet)
335 {
336         std::ostringstream caseList;
337         XE_CHECK(testSet.hasNode(m_root));
338         XE_CHECK(m_root->getNodeType() == TESTNODETYPE_ROOT);
339         writeCaseListNode(caseList, m_root, testSet);
340
341         m_commLink->startTestProcess(m_config.binaryName.c_str(), m_config.cmdLineArgs.c_str(), m_config.workingDir.c_str(), caseList.str().c_str());
342 }
343
344 void BatchExecutor::enqueueStateChanged (void* userPtr, CommLinkState state, const char* message)
345 {
346         BatchExecutor*  executor        = static_cast<BatchExecutor*>(userPtr);
347         CallWriter              writer          (&executor->m_dispatcher, BatchExecutor::dispatchStateChanged);
348
349         writer << executor
350                    << state
351                    << message;
352
353         writer.enqueue();
354 }
355
356 void BatchExecutor::enqueueTestLogData (void* userPtr, const deUint8* bytes, int numBytes)
357 {
358         BatchExecutor*  executor        = static_cast<BatchExecutor*>(userPtr);
359         CallWriter              writer          (&executor->m_dispatcher, BatchExecutor::dispatchTestLogData);
360
361         writer << executor
362                    << numBytes;
363
364         writer.write(bytes, numBytes);
365         writer.enqueue();
366 }
367
368 void BatchExecutor::enqueueInfoLogData (void* userPtr, const deUint8* bytes, int numBytes)
369 {
370         BatchExecutor*  executor        = static_cast<BatchExecutor*>(userPtr);
371         CallWriter              writer          (&executor->m_dispatcher, BatchExecutor::dispatchInfoLogData);
372
373         writer << executor
374                    << numBytes;
375
376         writer.write(bytes, numBytes);
377         writer.enqueue();
378 }
379
380 void BatchExecutor::dispatchStateChanged (CallReader data)
381 {
382         BatchExecutor*  executor        = DE_NULL;
383         CommLinkState   state           = COMMLINKSTATE_LAST;
384         std::string             message;
385
386         data >> executor
387                  >> state
388                  >> message;
389
390         executor->onStateChanged(state, message.c_str());
391 }
392
393 void BatchExecutor::dispatchTestLogData (CallReader data)
394 {
395         BatchExecutor*  executor        = DE_NULL;
396         int                             numBytes;
397
398         data >> executor
399                  >> numBytes;
400
401         executor->onTestLogData(data.getDataBlock(numBytes), numBytes);
402 }
403
404 void BatchExecutor::dispatchInfoLogData (CallReader data)
405 {
406         BatchExecutor*  executor        = DE_NULL;
407         int                             numBytes;
408
409         data >> executor
410                  >> numBytes;
411
412         executor->onInfoLogData(data.getDataBlock(numBytes), numBytes);
413 }
414
415 } // xe