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