xref: /aosp_15_r20/external/deqp/framework/common/tcuThreadUtil.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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