xref: /aosp_15_r20/external/deqp/framework/delibs/decpp/deThreadSafeRingBuffer.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1*35238bceSAndroid Build Coastguard Worker /*-------------------------------------------------------------------------
2*35238bceSAndroid Build Coastguard Worker  * drawElements C++ Base Library
3*35238bceSAndroid Build Coastguard Worker  * -----------------------------
4*35238bceSAndroid Build Coastguard Worker  *
5*35238bceSAndroid Build Coastguard Worker  * Copyright 2014 The Android Open Source Project
6*35238bceSAndroid Build Coastguard Worker  *
7*35238bceSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
8*35238bceSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
9*35238bceSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
10*35238bceSAndroid Build Coastguard Worker  *
11*35238bceSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
12*35238bceSAndroid Build Coastguard Worker  *
13*35238bceSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
14*35238bceSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
15*35238bceSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16*35238bceSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
17*35238bceSAndroid Build Coastguard Worker  * limitations under the License.
18*35238bceSAndroid Build Coastguard Worker  *
19*35238bceSAndroid Build Coastguard Worker  *//*!
20*35238bceSAndroid Build Coastguard Worker  * \file
21*35238bceSAndroid Build Coastguard Worker  * \brief Thread-safe ring buffer template.
22*35238bceSAndroid Build Coastguard Worker  *//*--------------------------------------------------------------------*/
23*35238bceSAndroid Build Coastguard Worker 
24*35238bceSAndroid Build Coastguard Worker #include "deThreadSafeRingBuffer.hpp"
25*35238bceSAndroid Build Coastguard Worker #include "deRandom.hpp"
26*35238bceSAndroid Build Coastguard Worker #include "deThread.hpp"
27*35238bceSAndroid Build Coastguard Worker 
28*35238bceSAndroid Build Coastguard Worker #include <vector>
29*35238bceSAndroid Build Coastguard Worker 
30*35238bceSAndroid Build Coastguard Worker using std::vector;
31*35238bceSAndroid Build Coastguard Worker 
32*35238bceSAndroid Build Coastguard Worker namespace de
33*35238bceSAndroid Build Coastguard Worker {
34*35238bceSAndroid Build Coastguard Worker 
35*35238bceSAndroid Build Coastguard Worker namespace
36*35238bceSAndroid Build Coastguard Worker {
37*35238bceSAndroid Build Coastguard Worker 
38*35238bceSAndroid Build Coastguard Worker struct Message
39*35238bceSAndroid Build Coastguard Worker {
40*35238bceSAndroid Build Coastguard Worker     uint32_t data;
41*35238bceSAndroid Build Coastguard Worker 
Messagede::__anon331c95750111::Message42*35238bceSAndroid Build Coastguard Worker     Message(uint16_t threadId, uint16_t payload) : data((threadId << 16) | payload)
43*35238bceSAndroid Build Coastguard Worker     {
44*35238bceSAndroid Build Coastguard Worker     }
45*35238bceSAndroid Build Coastguard Worker 
Messagede::__anon331c95750111::Message46*35238bceSAndroid Build Coastguard Worker     Message(void) : data(0)
47*35238bceSAndroid Build Coastguard Worker     {
48*35238bceSAndroid Build Coastguard Worker     }
49*35238bceSAndroid Build Coastguard Worker 
getThreadIdde::__anon331c95750111::Message50*35238bceSAndroid Build Coastguard Worker     uint16_t getThreadId(void) const
51*35238bceSAndroid Build Coastguard Worker     {
52*35238bceSAndroid Build Coastguard Worker         return (uint16_t)(data >> 16);
53*35238bceSAndroid Build Coastguard Worker     }
getPayloadde::__anon331c95750111::Message54*35238bceSAndroid Build Coastguard Worker     uint16_t getPayload(void) const
55*35238bceSAndroid Build Coastguard Worker     {
56*35238bceSAndroid Build Coastguard Worker         return (uint16_t)(data & 0xffff);
57*35238bceSAndroid Build Coastguard Worker     }
58*35238bceSAndroid Build Coastguard Worker };
59*35238bceSAndroid Build Coastguard Worker 
60*35238bceSAndroid Build Coastguard Worker class Consumer : public Thread
61*35238bceSAndroid Build Coastguard Worker {
62*35238bceSAndroid Build Coastguard Worker public:
Consumer(ThreadSafeRingBuffer<Message> & buffer,int numProducers)63*35238bceSAndroid Build Coastguard Worker     Consumer(ThreadSafeRingBuffer<Message> &buffer, int numProducers) : m_buffer(buffer)
64*35238bceSAndroid Build Coastguard Worker     {
65*35238bceSAndroid Build Coastguard Worker         m_lastPayload.resize(numProducers, 0);
66*35238bceSAndroid Build Coastguard Worker         m_payloadSum.resize(numProducers, 0);
67*35238bceSAndroid Build Coastguard Worker     }
68*35238bceSAndroid Build Coastguard Worker 
run(void)69*35238bceSAndroid Build Coastguard Worker     void run(void)
70*35238bceSAndroid Build Coastguard Worker     {
71*35238bceSAndroid Build Coastguard Worker         for (;;)
72*35238bceSAndroid Build Coastguard Worker         {
73*35238bceSAndroid Build Coastguard Worker             Message msg = m_buffer.popBack();
74*35238bceSAndroid Build Coastguard Worker 
75*35238bceSAndroid Build Coastguard Worker             uint16_t threadId = msg.getThreadId();
76*35238bceSAndroid Build Coastguard Worker 
77*35238bceSAndroid Build Coastguard Worker             if (threadId == 0xffff)
78*35238bceSAndroid Build Coastguard Worker                 break;
79*35238bceSAndroid Build Coastguard Worker 
80*35238bceSAndroid Build Coastguard Worker             DE_TEST_ASSERT(de::inBounds<int>(threadId, 0, (int)m_lastPayload.size()));
81*35238bceSAndroid Build Coastguard Worker             DE_TEST_ASSERT((m_lastPayload[threadId] == 0 && msg.getPayload() == 0) ||
82*35238bceSAndroid Build Coastguard Worker                            m_lastPayload[threadId] < msg.getPayload());
83*35238bceSAndroid Build Coastguard Worker 
84*35238bceSAndroid Build Coastguard Worker             m_lastPayload[threadId] = msg.getPayload();
85*35238bceSAndroid Build Coastguard Worker             m_payloadSum[threadId] += (uint32_t)msg.getPayload();
86*35238bceSAndroid Build Coastguard Worker         }
87*35238bceSAndroid Build Coastguard Worker     }
88*35238bceSAndroid Build Coastguard Worker 
getPayloadSum(uint16_t threadId) const89*35238bceSAndroid Build Coastguard Worker     uint32_t getPayloadSum(uint16_t threadId) const
90*35238bceSAndroid Build Coastguard Worker     {
91*35238bceSAndroid Build Coastguard Worker         return m_payloadSum[threadId];
92*35238bceSAndroid Build Coastguard Worker     }
93*35238bceSAndroid Build Coastguard Worker 
94*35238bceSAndroid Build Coastguard Worker private:
95*35238bceSAndroid Build Coastguard Worker     ThreadSafeRingBuffer<Message> &m_buffer;
96*35238bceSAndroid Build Coastguard Worker     vector<uint16_t> m_lastPayload;
97*35238bceSAndroid Build Coastguard Worker     vector<uint32_t> m_payloadSum;
98*35238bceSAndroid Build Coastguard Worker };
99*35238bceSAndroid Build Coastguard Worker 
100*35238bceSAndroid Build Coastguard Worker class Producer : public Thread
101*35238bceSAndroid Build Coastguard Worker {
102*35238bceSAndroid Build Coastguard Worker public:
Producer(ThreadSafeRingBuffer<Message> & buffer,uint16_t threadId,int dataSize)103*35238bceSAndroid Build Coastguard Worker     Producer(ThreadSafeRingBuffer<Message> &buffer, uint16_t threadId, int dataSize)
104*35238bceSAndroid Build Coastguard Worker         : m_buffer(buffer)
105*35238bceSAndroid Build Coastguard Worker         , m_threadId(threadId)
106*35238bceSAndroid Build Coastguard Worker         , m_dataSize(dataSize)
107*35238bceSAndroid Build Coastguard Worker     {
108*35238bceSAndroid Build Coastguard Worker     }
109*35238bceSAndroid Build Coastguard Worker 
run(void)110*35238bceSAndroid Build Coastguard Worker     void run(void)
111*35238bceSAndroid Build Coastguard Worker     {
112*35238bceSAndroid Build Coastguard Worker         // Yield to give main thread chance to start other producers.
113*35238bceSAndroid Build Coastguard Worker         deSleep(1);
114*35238bceSAndroid Build Coastguard Worker 
115*35238bceSAndroid Build Coastguard Worker         for (int ndx = 0; ndx < m_dataSize; ndx++)
116*35238bceSAndroid Build Coastguard Worker             m_buffer.pushFront(Message(m_threadId, (uint16_t)ndx));
117*35238bceSAndroid Build Coastguard Worker     }
118*35238bceSAndroid Build Coastguard Worker 
119*35238bceSAndroid Build Coastguard Worker private:
120*35238bceSAndroid Build Coastguard Worker     ThreadSafeRingBuffer<Message> &m_buffer;
121*35238bceSAndroid Build Coastguard Worker     uint16_t m_threadId;
122*35238bceSAndroid Build Coastguard Worker     int m_dataSize;
123*35238bceSAndroid Build Coastguard Worker };
124*35238bceSAndroid Build Coastguard Worker 
125*35238bceSAndroid Build Coastguard Worker } // namespace
126*35238bceSAndroid Build Coastguard Worker 
ThreadSafeRingBuffer_selfTest(void)127*35238bceSAndroid Build Coastguard Worker void ThreadSafeRingBuffer_selfTest(void)
128*35238bceSAndroid Build Coastguard Worker {
129*35238bceSAndroid Build Coastguard Worker     const int numIterations = 16;
130*35238bceSAndroid Build Coastguard Worker     for (int iterNdx = 0; iterNdx < numIterations; iterNdx++)
131*35238bceSAndroid Build Coastguard Worker     {
132*35238bceSAndroid Build Coastguard Worker         Random rnd(iterNdx);
133*35238bceSAndroid Build Coastguard Worker         int bufSize      = rnd.getInt(1, 2048);
134*35238bceSAndroid Build Coastguard Worker         int numProducers = rnd.getInt(1, 16);
135*35238bceSAndroid Build Coastguard Worker         int numConsumers = rnd.getInt(1, 16);
136*35238bceSAndroid Build Coastguard Worker         int dataSize     = rnd.getInt(1000, 10000);
137*35238bceSAndroid Build Coastguard Worker         ThreadSafeRingBuffer<Message> buffer(bufSize);
138*35238bceSAndroid Build Coastguard Worker         vector<Producer *> producers;
139*35238bceSAndroid Build Coastguard Worker         vector<Consumer *> consumers;
140*35238bceSAndroid Build Coastguard Worker 
141*35238bceSAndroid Build Coastguard Worker         for (int i = 0; i < numProducers; i++)
142*35238bceSAndroid Build Coastguard Worker             producers.push_back(new Producer(buffer, (uint16_t)i, dataSize));
143*35238bceSAndroid Build Coastguard Worker 
144*35238bceSAndroid Build Coastguard Worker         for (int i = 0; i < numConsumers; i++)
145*35238bceSAndroid Build Coastguard Worker             consumers.push_back(new Consumer(buffer, numProducers));
146*35238bceSAndroid Build Coastguard Worker 
147*35238bceSAndroid Build Coastguard Worker         // Start consumers.
148*35238bceSAndroid Build Coastguard Worker         for (vector<Consumer *>::iterator i = consumers.begin(); i != consumers.end(); i++)
149*35238bceSAndroid Build Coastguard Worker             (*i)->start();
150*35238bceSAndroid Build Coastguard Worker 
151*35238bceSAndroid Build Coastguard Worker         // Start producers.
152*35238bceSAndroid Build Coastguard Worker         for (vector<Producer *>::iterator i = producers.begin(); i != producers.end(); i++)
153*35238bceSAndroid Build Coastguard Worker             (*i)->start();
154*35238bceSAndroid Build Coastguard Worker 
155*35238bceSAndroid Build Coastguard Worker         // Wait for producers.
156*35238bceSAndroid Build Coastguard Worker         for (vector<Producer *>::iterator i = producers.begin(); i != producers.end(); i++)
157*35238bceSAndroid Build Coastguard Worker             (*i)->join();
158*35238bceSAndroid Build Coastguard Worker 
159*35238bceSAndroid Build Coastguard Worker         // Write end messages for consumers.
160*35238bceSAndroid Build Coastguard Worker         for (int i = 0; i < numConsumers; i++)
161*35238bceSAndroid Build Coastguard Worker             buffer.pushFront(Message(0xffff, 0));
162*35238bceSAndroid Build Coastguard Worker 
163*35238bceSAndroid Build Coastguard Worker         // Wait for consumers.
164*35238bceSAndroid Build Coastguard Worker         for (vector<Consumer *>::iterator i = consumers.begin(); i != consumers.end(); i++)
165*35238bceSAndroid Build Coastguard Worker             (*i)->join();
166*35238bceSAndroid Build Coastguard Worker 
167*35238bceSAndroid Build Coastguard Worker         // Verify payload sums.
168*35238bceSAndroid Build Coastguard Worker         uint32_t refSum = 0;
169*35238bceSAndroid Build Coastguard Worker         for (int i = 0; i < dataSize; i++)
170*35238bceSAndroid Build Coastguard Worker             refSum += (uint32_t)(uint16_t)i;
171*35238bceSAndroid Build Coastguard Worker 
172*35238bceSAndroid Build Coastguard Worker         for (int i = 0; i < numProducers; i++)
173*35238bceSAndroid Build Coastguard Worker         {
174*35238bceSAndroid Build Coastguard Worker             uint32_t cmpSum = 0;
175*35238bceSAndroid Build Coastguard Worker             for (int j = 0; j < numConsumers; j++)
176*35238bceSAndroid Build Coastguard Worker                 cmpSum += consumers[j]->getPayloadSum((uint16_t)i);
177*35238bceSAndroid Build Coastguard Worker             DE_TEST_ASSERT(refSum == cmpSum);
178*35238bceSAndroid Build Coastguard Worker         }
179*35238bceSAndroid Build Coastguard Worker 
180*35238bceSAndroid Build Coastguard Worker         // Free resources.
181*35238bceSAndroid Build Coastguard Worker         for (vector<Producer *>::iterator i = producers.begin(); i != producers.end(); i++)
182*35238bceSAndroid Build Coastguard Worker             delete *i;
183*35238bceSAndroid Build Coastguard Worker         for (vector<Consumer *>::iterator i = consumers.begin(); i != consumers.end(); i++)
184*35238bceSAndroid Build Coastguard Worker             delete *i;
185*35238bceSAndroid Build Coastguard Worker     }
186*35238bceSAndroid Build Coastguard Worker }
187*35238bceSAndroid Build Coastguard Worker 
188*35238bceSAndroid Build Coastguard Worker } // namespace de
189