1*89c4ff92SAndroid Build Coastguard Worker //
2*89c4ff92SAndroid Build Coastguard Worker // Copyright © 2019 Arm Ltd. All rights reserved.
3*89c4ff92SAndroid Build Coastguard Worker // SPDX-License-Identifier: MIT
4*89c4ff92SAndroid Build Coastguard Worker //
5*89c4ff92SAndroid Build Coastguard Worker
6*89c4ff92SAndroid Build Coastguard Worker #include "BufferManager.hpp"
7*89c4ff92SAndroid Build Coastguard Worker #include "PacketBuffer.hpp"
8*89c4ff92SAndroid Build Coastguard Worker
9*89c4ff92SAndroid Build Coastguard Worker namespace arm
10*89c4ff92SAndroid Build Coastguard Worker {
11*89c4ff92SAndroid Build Coastguard Worker
12*89c4ff92SAndroid Build Coastguard Worker namespace pipe
13*89c4ff92SAndroid Build Coastguard Worker {
14*89c4ff92SAndroid Build Coastguard Worker
BufferManager(unsigned int numberOfBuffers,unsigned int maxPacketSize)15*89c4ff92SAndroid Build Coastguard Worker BufferManager::BufferManager(unsigned int numberOfBuffers, unsigned int maxPacketSize)
16*89c4ff92SAndroid Build Coastguard Worker : m_MaxBufferSize(maxPacketSize),
17*89c4ff92SAndroid Build Coastguard Worker m_NumberOfBuffers(numberOfBuffers),
18*89c4ff92SAndroid Build Coastguard Worker m_MaxNumberOfBuffers(numberOfBuffers * 3),
19*89c4ff92SAndroid Build Coastguard Worker m_CurrentNumberOfBuffers(numberOfBuffers)
20*89c4ff92SAndroid Build Coastguard Worker {
21*89c4ff92SAndroid Build Coastguard Worker Initialize();
22*89c4ff92SAndroid Build Coastguard Worker }
23*89c4ff92SAndroid Build Coastguard Worker
Reserve(unsigned int requestedSize,unsigned int & reservedSize)24*89c4ff92SAndroid Build Coastguard Worker IPacketBufferPtr BufferManager::Reserve(unsigned int requestedSize, unsigned int& reservedSize)
25*89c4ff92SAndroid Build Coastguard Worker {
26*89c4ff92SAndroid Build Coastguard Worker reservedSize = 0;
27*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
28*89c4ff92SAndroid Build Coastguard Worker std::unique_lock<std::mutex> availableListLock(m_AvailableMutex, std::defer_lock);
29*89c4ff92SAndroid Build Coastguard Worker #endif
30*89c4ff92SAndroid Build Coastguard Worker if (requestedSize > m_MaxBufferSize)
31*89c4ff92SAndroid Build Coastguard Worker {
32*89c4ff92SAndroid Build Coastguard Worker return nullptr;
33*89c4ff92SAndroid Build Coastguard Worker }
34*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
35*89c4ff92SAndroid Build Coastguard Worker availableListLock.lock();
36*89c4ff92SAndroid Build Coastguard Worker #endif
37*89c4ff92SAndroid Build Coastguard Worker if (m_AvailableList.empty())
38*89c4ff92SAndroid Build Coastguard Worker {
39*89c4ff92SAndroid Build Coastguard Worker if (m_CurrentNumberOfBuffers < m_MaxNumberOfBuffers)
40*89c4ff92SAndroid Build Coastguard Worker {
41*89c4ff92SAndroid Build Coastguard Worker // create a temporary overflow/surge buffer and hand it back
42*89c4ff92SAndroid Build Coastguard Worker m_CurrentNumberOfBuffers++;
43*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
44*89c4ff92SAndroid Build Coastguard Worker availableListLock.unlock();
45*89c4ff92SAndroid Build Coastguard Worker #endif
46*89c4ff92SAndroid Build Coastguard Worker IPacketBufferPtr buffer = std::make_unique<PacketBuffer>(m_MaxBufferSize);
47*89c4ff92SAndroid Build Coastguard Worker reservedSize = requestedSize;
48*89c4ff92SAndroid Build Coastguard Worker return buffer;
49*89c4ff92SAndroid Build Coastguard Worker }
50*89c4ff92SAndroid Build Coastguard Worker else
51*89c4ff92SAndroid Build Coastguard Worker {
52*89c4ff92SAndroid Build Coastguard Worker // we have totally busted the limit. call a halt to new memory allocations.
53*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
54*89c4ff92SAndroid Build Coastguard Worker availableListLock.unlock();
55*89c4ff92SAndroid Build Coastguard Worker #endif
56*89c4ff92SAndroid Build Coastguard Worker return nullptr;
57*89c4ff92SAndroid Build Coastguard Worker }
58*89c4ff92SAndroid Build Coastguard Worker }
59*89c4ff92SAndroid Build Coastguard Worker IPacketBufferPtr buffer = std::move(m_AvailableList.back());
60*89c4ff92SAndroid Build Coastguard Worker m_AvailableList.pop_back();
61*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
62*89c4ff92SAndroid Build Coastguard Worker availableListLock.unlock();
63*89c4ff92SAndroid Build Coastguard Worker #endif
64*89c4ff92SAndroid Build Coastguard Worker reservedSize = requestedSize;
65*89c4ff92SAndroid Build Coastguard Worker return buffer;
66*89c4ff92SAndroid Build Coastguard Worker }
67*89c4ff92SAndroid Build Coastguard Worker
Commit(IPacketBufferPtr & packetBuffer,unsigned int size,bool notifyConsumer)68*89c4ff92SAndroid Build Coastguard Worker void BufferManager::Commit(IPacketBufferPtr& packetBuffer, unsigned int size, bool notifyConsumer)
69*89c4ff92SAndroid Build Coastguard Worker {
70*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
71*89c4ff92SAndroid Build Coastguard Worker std::unique_lock<std::mutex> readableListLock(m_ReadableMutex, std::defer_lock);
72*89c4ff92SAndroid Build Coastguard Worker #endif
73*89c4ff92SAndroid Build Coastguard Worker packetBuffer->Commit(size);
74*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
75*89c4ff92SAndroid Build Coastguard Worker readableListLock.lock();
76*89c4ff92SAndroid Build Coastguard Worker #endif
77*89c4ff92SAndroid Build Coastguard Worker m_ReadableList.push(std::move(packetBuffer));
78*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
79*89c4ff92SAndroid Build Coastguard Worker readableListLock.unlock();
80*89c4ff92SAndroid Build Coastguard Worker #endif
81*89c4ff92SAndroid Build Coastguard Worker if (notifyConsumer)
82*89c4ff92SAndroid Build Coastguard Worker {
83*89c4ff92SAndroid Build Coastguard Worker FlushReadList();
84*89c4ff92SAndroid Build Coastguard Worker }
85*89c4ff92SAndroid Build Coastguard Worker }
86*89c4ff92SAndroid Build Coastguard Worker
Initialize()87*89c4ff92SAndroid Build Coastguard Worker void BufferManager::Initialize()
88*89c4ff92SAndroid Build Coastguard Worker {
89*89c4ff92SAndroid Build Coastguard Worker m_AvailableList.reserve(m_NumberOfBuffers);
90*89c4ff92SAndroid Build Coastguard Worker m_CurrentNumberOfBuffers = m_NumberOfBuffers;
91*89c4ff92SAndroid Build Coastguard Worker for (unsigned int i = 0; i < m_NumberOfBuffers; ++i)
92*89c4ff92SAndroid Build Coastguard Worker {
93*89c4ff92SAndroid Build Coastguard Worker IPacketBufferPtr buffer = std::make_unique<PacketBuffer>(m_MaxBufferSize);
94*89c4ff92SAndroid Build Coastguard Worker m_AvailableList.emplace_back(std::move(buffer));
95*89c4ff92SAndroid Build Coastguard Worker }
96*89c4ff92SAndroid Build Coastguard Worker }
97*89c4ff92SAndroid Build Coastguard Worker
Release(IPacketBufferPtr & packetBuffer)98*89c4ff92SAndroid Build Coastguard Worker void BufferManager::Release(IPacketBufferPtr& packetBuffer)
99*89c4ff92SAndroid Build Coastguard Worker {
100*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
101*89c4ff92SAndroid Build Coastguard Worker std::unique_lock<std::mutex> availableListLock(m_AvailableMutex, std::defer_lock);
102*89c4ff92SAndroid Build Coastguard Worker #endif
103*89c4ff92SAndroid Build Coastguard Worker packetBuffer->Release();
104*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
105*89c4ff92SAndroid Build Coastguard Worker availableListLock.lock();
106*89c4ff92SAndroid Build Coastguard Worker #endif
107*89c4ff92SAndroid Build Coastguard Worker if (m_AvailableList.size() <= m_NumberOfBuffers)
108*89c4ff92SAndroid Build Coastguard Worker {
109*89c4ff92SAndroid Build Coastguard Worker m_AvailableList.push_back(std::move(packetBuffer));
110*89c4ff92SAndroid Build Coastguard Worker }
111*89c4ff92SAndroid Build Coastguard Worker else
112*89c4ff92SAndroid Build Coastguard Worker {
113*89c4ff92SAndroid Build Coastguard Worker // we have been handed a temporary overflow/surge buffer get rid of it
114*89c4ff92SAndroid Build Coastguard Worker packetBuffer->Destroy();
115*89c4ff92SAndroid Build Coastguard Worker if (m_CurrentNumberOfBuffers > m_NumberOfBuffers)
116*89c4ff92SAndroid Build Coastguard Worker {
117*89c4ff92SAndroid Build Coastguard Worker --m_CurrentNumberOfBuffers;
118*89c4ff92SAndroid Build Coastguard Worker }
119*89c4ff92SAndroid Build Coastguard Worker }
120*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
121*89c4ff92SAndroid Build Coastguard Worker availableListLock.unlock();
122*89c4ff92SAndroid Build Coastguard Worker #endif
123*89c4ff92SAndroid Build Coastguard Worker }
124*89c4ff92SAndroid Build Coastguard Worker
Reset()125*89c4ff92SAndroid Build Coastguard Worker void BufferManager::Reset()
126*89c4ff92SAndroid Build Coastguard Worker {
127*89c4ff92SAndroid Build Coastguard Worker //This method should only be called once all threads have been joined
128*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
129*89c4ff92SAndroid Build Coastguard Worker std::lock_guard<std::mutex> readableListLock(m_ReadableMutex);
130*89c4ff92SAndroid Build Coastguard Worker std::lock_guard<std::mutex> availableListLock(m_AvailableMutex);
131*89c4ff92SAndroid Build Coastguard Worker #endif
132*89c4ff92SAndroid Build Coastguard Worker
133*89c4ff92SAndroid Build Coastguard Worker m_AvailableList.clear();
134*89c4ff92SAndroid Build Coastguard Worker std::queue<IPacketBufferPtr>().swap(m_ReadableList);
135*89c4ff92SAndroid Build Coastguard Worker
136*89c4ff92SAndroid Build Coastguard Worker Initialize();
137*89c4ff92SAndroid Build Coastguard Worker }
138*89c4ff92SAndroid Build Coastguard Worker
GetReadableBuffer()139*89c4ff92SAndroid Build Coastguard Worker IPacketBufferPtr BufferManager::GetReadableBuffer()
140*89c4ff92SAndroid Build Coastguard Worker {
141*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
142*89c4ff92SAndroid Build Coastguard Worker std::unique_lock<std::mutex> readableListLock(m_ReadableMutex);
143*89c4ff92SAndroid Build Coastguard Worker #endif
144*89c4ff92SAndroid Build Coastguard Worker if (!m_ReadableList.empty())
145*89c4ff92SAndroid Build Coastguard Worker {
146*89c4ff92SAndroid Build Coastguard Worker IPacketBufferPtr buffer = std::move(m_ReadableList.front());
147*89c4ff92SAndroid Build Coastguard Worker m_ReadableList.pop();
148*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
149*89c4ff92SAndroid Build Coastguard Worker readableListLock.unlock();
150*89c4ff92SAndroid Build Coastguard Worker #endif
151*89c4ff92SAndroid Build Coastguard Worker return buffer;
152*89c4ff92SAndroid Build Coastguard Worker }
153*89c4ff92SAndroid Build Coastguard Worker return nullptr;
154*89c4ff92SAndroid Build Coastguard Worker }
155*89c4ff92SAndroid Build Coastguard Worker
MarkRead(IPacketBufferPtr & packetBuffer)156*89c4ff92SAndroid Build Coastguard Worker void BufferManager::MarkRead(IPacketBufferPtr& packetBuffer)
157*89c4ff92SAndroid Build Coastguard Worker {
158*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
159*89c4ff92SAndroid Build Coastguard Worker std::unique_lock<std::mutex> availableListLock(m_AvailableMutex, std::defer_lock);
160*89c4ff92SAndroid Build Coastguard Worker #endif
161*89c4ff92SAndroid Build Coastguard Worker packetBuffer->MarkRead();
162*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
163*89c4ff92SAndroid Build Coastguard Worker availableListLock.lock();
164*89c4ff92SAndroid Build Coastguard Worker #endif
165*89c4ff92SAndroid Build Coastguard Worker if (m_AvailableList.size() <= m_NumberOfBuffers)
166*89c4ff92SAndroid Build Coastguard Worker {
167*89c4ff92SAndroid Build Coastguard Worker m_AvailableList.push_back(std::move(packetBuffer));
168*89c4ff92SAndroid Build Coastguard Worker }
169*89c4ff92SAndroid Build Coastguard Worker else
170*89c4ff92SAndroid Build Coastguard Worker {
171*89c4ff92SAndroid Build Coastguard Worker // we have been handed a temporary overflow/surge buffer get rid of it
172*89c4ff92SAndroid Build Coastguard Worker packetBuffer->Destroy();
173*89c4ff92SAndroid Build Coastguard Worker if (m_CurrentNumberOfBuffers > m_NumberOfBuffers)
174*89c4ff92SAndroid Build Coastguard Worker {
175*89c4ff92SAndroid Build Coastguard Worker --m_CurrentNumberOfBuffers;
176*89c4ff92SAndroid Build Coastguard Worker }
177*89c4ff92SAndroid Build Coastguard Worker }
178*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_THREADS)
179*89c4ff92SAndroid Build Coastguard Worker availableListLock.unlock();
180*89c4ff92SAndroid Build Coastguard Worker #endif
181*89c4ff92SAndroid Build Coastguard Worker }
182*89c4ff92SAndroid Build Coastguard Worker
SetConsumer(IConsumer * consumer)183*89c4ff92SAndroid Build Coastguard Worker void BufferManager::SetConsumer(IConsumer* consumer)
184*89c4ff92SAndroid Build Coastguard Worker {
185*89c4ff92SAndroid Build Coastguard Worker m_Consumer = consumer;
186*89c4ff92SAndroid Build Coastguard Worker }
187*89c4ff92SAndroid Build Coastguard Worker
FlushReadList()188*89c4ff92SAndroid Build Coastguard Worker void BufferManager::FlushReadList()
189*89c4ff92SAndroid Build Coastguard Worker {
190*89c4ff92SAndroid Build Coastguard Worker // notify consumer that packet is ready to read
191*89c4ff92SAndroid Build Coastguard Worker if (m_Consumer != nullptr)
192*89c4ff92SAndroid Build Coastguard Worker {
193*89c4ff92SAndroid Build Coastguard Worker m_Consumer->SetReadyToRead();
194*89c4ff92SAndroid Build Coastguard Worker }
195*89c4ff92SAndroid Build Coastguard Worker }
196*89c4ff92SAndroid Build Coastguard Worker
197*89c4ff92SAndroid Build Coastguard Worker } // namespace pipe
198*89c4ff92SAndroid Build Coastguard Worker
199*89c4ff92SAndroid Build Coastguard Worker } // namespace arm
200