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