Merge vk-gl-cts/vulkan-cts-1.2.0 into vk-gl-cts/vulkan-cts-1.2.1
[platform/upstream/VK-GL-CTS.git] / framework / common / tcuThreadUtil.cpp
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 Thread test utilities
22  *//*--------------------------------------------------------------------*/
23
24 #include "tcuThreadUtil.hpp"
25
26 #include "deClock.h"
27 #include "deMemory.h"
28
29 using std::vector;
30 using de::SharedPtr;
31
32 namespace tcu
33 {
34 namespace ThreadUtil
35 {
36
37 Event::Event (void)
38         : m_result              (RESULT_NOT_READY)
39         , m_waiterCount (0)
40         , m_waiters             (0, 0)
41 {
42 }
43
44 Event::~Event (void)
45 {
46 }
47
48 void Event::setResult (Result result)
49 {
50         m_lock.lock();
51         DE_ASSERT(m_result == RESULT_NOT_READY);
52         m_result = result;
53         m_lock.unlock();
54
55         for (int i = 0; i < m_waiterCount; i++)
56                 m_waiters.increment();
57 }
58
59 Event::Result Event::waitReady (void)
60 {
61         m_lock.lock();
62
63         if (m_result == RESULT_NOT_READY)
64                 m_waiterCount++;
65         else
66         {
67                 m_lock.unlock();
68                 return m_result;
69         }
70
71         m_lock.unlock();
72
73         m_waiters.decrement();
74
75         return m_result;
76 }
77
78 Object::Object (const char* type, SharedPtr<Event> e)
79         : m_type        (type)
80         , m_modify      (e)
81 {
82 }
83
84 Object::~Object (void)
85 {
86 }
87
88 void Object::read (SharedPtr<Event> event, std::vector<SharedPtr<Event> >& deps)
89 {
90         // Make call depend on last modifying call
91         deps.push_back(m_modify);
92
93         // Add read dependency
94         m_reads.push_back(event);
95 }
96
97 void Object::modify (SharedPtr<Event> event, std::vector<SharedPtr<Event> >& deps)
98 {
99         // Make call depend on all reads
100         for (int readNdx = 0; readNdx < (int)m_reads.size(); readNdx++)
101         {
102                 deps.push_back(m_reads[readNdx]);
103         }
104         deps.push_back(m_modify);
105
106         // Update last modifying call
107         m_modify = event;
108
109         // Clear read dependencies of last "version" of this object
110         m_reads.clear();
111 }
112
113 Operation::Operation (const char* name)
114         : m_name        (name)
115         , m_event       (new Event)
116 {
117 }
118
119 Operation::~Operation (void)
120 {
121 }
122
123 void Operation::execute (Thread& thread)
124 {
125         bool success = true;
126
127         // Wait for dependencies and check that they succeeded
128         for (int depNdx = 0; depNdx < (int)m_deps.size(); depNdx++)
129         {
130                 if (m_deps[depNdx]->waitReady() != Event::RESULT_OK)
131                         success = false;
132         }
133
134         // Try execute operation
135         if (success)
136         {
137                 try
138                 {
139                         exec(thread);
140                 }
141                 catch (...)
142                 {
143                         // Got exception event failed
144                         m_event->setResult(Event::RESULT_FAILED);
145                         throw;
146                 }
147
148                 m_event->setResult(Event::RESULT_OK);
149         }
150         else
151                 // Some dependencies failed
152                 m_event->setResult(Event::RESULT_FAILED);
153
154         // Release resources
155         m_deps.clear();
156         m_event = SharedPtr<Event>();
157 }
158
159 const MessageBuilder::EndToken Message::End = MessageBuilder::EndToken();
160
161 void MessageBuilder::operator<< (const EndToken&)
162 {
163         m_thread.pushMessage(m_stream.str());
164 }
165
166 Thread::Thread (deUint32 seed)
167         : m_random      (seed)
168         , m_status      (THREADSTATUS_NOT_STARTED)
169 {
170 }
171
172 Thread::~Thread (void)
173 {
174         for (int operationNdx = 0; operationNdx < (int)m_operations.size(); operationNdx++)
175                 delete m_operations[operationNdx];
176
177         m_operations.clear();
178 }
179
180 deUint8* Thread::getDummyData (size_t size)
181 {
182         if (m_dummyData.size() < size)
183         {
184                 m_dummyData.resize(size);
185         }
186
187         return &(m_dummyData[0]);
188 }
189
190 void Thread::addOperation (Operation* operation)
191 {
192         m_operations.push_back(operation);
193 }
194
195 void Thread::run (void)
196 {
197         setStatus(THREADSTATUS_RUNNING);
198         bool initOk = false;
199
200         // Reserve at least two messages for each operation
201         m_messages.reserve(m_operations.size()*2);
202         try
203         {
204                 init();
205                 initOk = true;
206                 for (int operationNdx = 0; operationNdx < (int)m_operations.size(); operationNdx++)
207                         m_operations[operationNdx]->execute(*this);
208
209                 deinit();
210                 setStatus(THREADSTATUS_READY);
211         }
212         catch (const tcu::NotSupportedError& e)
213         {
214                 newMessage() << "tcu::NotSupportedError '" << e.what() << "'" << Message::End;
215                 deinit();
216                 setStatus(initOk ? THREADSTATUS_NOT_SUPPORTED : THREADSTATUS_INIT_FAILED);
217         }
218         catch (const tcu::Exception& e)
219         {
220                 newMessage() << "tcu::Exception '" << e.what() << "'" << Message::End;
221                 deinit();
222                 setStatus(initOk ? THREADSTATUS_FAILED : THREADSTATUS_INIT_FAILED);
223         }
224         catch (const std::exception& error)
225         {
226                 newMessage() << "std::exception '" << error.what() << "'" << Message::End;
227                 deinit();
228                 setStatus(initOk ? THREADSTATUS_FAILED : THREADSTATUS_INIT_FAILED);
229         }
230         catch (...)
231         {
232                 newMessage() << "Unkown exception" << Message::End;
233                 deinit();
234                 setStatus(initOk ? THREADSTATUS_FAILED : THREADSTATUS_INIT_FAILED);
235         }
236 }
237
238 void Thread::exec (void)
239 {
240         start();
241 }
242
243 void Thread::pushMessage (const std::string& str)
244 {
245         de::ScopedLock lock(m_messageLock);
246         m_messages.push_back(Message(deGetMicroseconds(), str.c_str()));
247 }
248
249 int Thread::getMessageCount      (void) const
250 {
251         de::ScopedLock lock(m_messageLock);
252         return (int)(m_messages.size());
253 }
254
255 Message Thread::getMessage (int index) const
256 {
257         de::ScopedLock lock(m_messageLock);
258         return m_messages[index];
259 }
260
261
262 DataBlock::DataBlock (SharedPtr<Event> event)
263         : Object("DataBlock", event)
264 {
265 }
266
267 void DataBlock::setData (size_t size, const void* data)
268 {
269         m_data = std::vector<deUint8>(size);
270         deMemcpy(&(m_data[0]), data, size);
271 }
272
273 CompareData::CompareData (SharedPtr<DataBlock> a, SharedPtr<DataBlock> b)
274         : Operation     ("CompareData")
275         , m_a           (a)
276         , m_b           (b)
277 {
278         readObject(SharedPtr<Object>(a));
279         readObject(SharedPtr<Object>(b));
280 }
281
282 void CompareData::exec (Thread& thread)
283 {
284         bool result = true;
285         DE_ASSERT(m_a->getSize() == m_b->getSize());
286
287         thread.newMessage() << "Begin -- CompareData" << Message::End;
288
289         for (int byteNdx = 0; byteNdx < (int)m_a->getSize(); byteNdx++)
290         {
291                 if (m_a->getData()[byteNdx] != m_b->getData()[byteNdx])
292                 {
293                         result = false;
294                         thread.newMessage() << "CompareData failed at offset :" << byteNdx << Message::End;
295                         break;
296                 }
297         }
298
299         if (result)
300                 thread.newMessage() << "CompareData passed" << Message::End;
301         else
302                 TCU_FAIL("Data comparision failed");
303
304         thread.newMessage() << "End -- CompareData" << Message::End;
305 }
306
307 } // ThreadUtil
308 } // tcu