ArmNN
 21.08
BufferManager.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2019 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "BufferManager.hpp"
7 #include "PacketBuffer.hpp"
8 
9 namespace armnn
10 {
11 
12 namespace profiling
13 {
14 
15 BufferManager::BufferManager(unsigned int numberOfBuffers, unsigned int maxPacketSize)
16  : m_MaxBufferSize(maxPacketSize),
17  m_NumberOfBuffers(numberOfBuffers),
18  m_MaxNumberOfBuffers(numberOfBuffers * 3),
19  m_CurrentNumberOfBuffers(numberOfBuffers)
20 {
21  Initialize();
22 }
23 
24 IPacketBufferPtr BufferManager::Reserve(unsigned int requestedSize, unsigned int& reservedSize)
25 {
26  reservedSize = 0;
27  std::unique_lock<std::mutex> availableListLock(m_AvailableMutex, std::defer_lock);
28  if (requestedSize > m_MaxBufferSize)
29  {
30  return nullptr;
31  }
32  availableListLock.lock();
33  if (m_AvailableList.empty())
34  {
35  if (m_CurrentNumberOfBuffers < m_MaxNumberOfBuffers)
36  {
37  // create a temporary overflow/surge buffer and hand it back
38  m_CurrentNumberOfBuffers++;
39  availableListLock.unlock();
40  IPacketBufferPtr buffer = std::make_unique<PacketBuffer>(m_MaxBufferSize);
41  reservedSize = requestedSize;
42  return buffer;
43  }
44  else
45  {
46  // we have totally busted the limit. call a halt to new memory allocations.
47  availableListLock.unlock();
48  return nullptr;
49  }
50  }
51  IPacketBufferPtr buffer = std::move(m_AvailableList.back());
52  m_AvailableList.pop_back();
53  availableListLock.unlock();
54  reservedSize = requestedSize;
55  return buffer;
56 }
57 
58 void BufferManager::Commit(IPacketBufferPtr& packetBuffer, unsigned int size, bool notifyConsumer)
59 {
60  std::unique_lock<std::mutex> readableListLock(m_ReadableMutex, std::defer_lock);
61  packetBuffer->Commit(size);
62  readableListLock.lock();
63  m_ReadableList.push(std::move(packetBuffer));
64  readableListLock.unlock();
65 
66  if (notifyConsumer)
67  {
68  FlushReadList();
69  }
70 }
71 
72 void BufferManager::Initialize()
73 {
74  m_AvailableList.reserve(m_NumberOfBuffers);
75  m_CurrentNumberOfBuffers = m_NumberOfBuffers;
76  for (unsigned int i = 0; i < m_NumberOfBuffers; ++i)
77  {
78  IPacketBufferPtr buffer = std::make_unique<PacketBuffer>(m_MaxBufferSize);
79  m_AvailableList.emplace_back(std::move(buffer));
80  }
81 }
82 
84 {
85  std::unique_lock<std::mutex> availableListLock(m_AvailableMutex, std::defer_lock);
86  packetBuffer->Release();
87  availableListLock.lock();
88  if (m_AvailableList.size() <= m_NumberOfBuffers)
89  {
90  m_AvailableList.push_back(std::move(packetBuffer));
91  }
92  else
93  {
94  // we have been handed a temporary overflow/surge buffer get rid of it
95  packetBuffer->Destroy();
96  if (m_CurrentNumberOfBuffers > m_NumberOfBuffers)
97  {
98  --m_CurrentNumberOfBuffers;
99  }
100  }
101  availableListLock.unlock();
102 }
103 
105 {
106  //This method should only be called once all threads have been joined
107  std::lock_guard<std::mutex> readableListLock(m_ReadableMutex);
108  std::lock_guard<std::mutex> availableListLock(m_AvailableMutex);
109 
110  m_AvailableList.clear();
111  std::queue<IPacketBufferPtr>().swap(m_ReadableList);
112 
113  Initialize();
114 }
115 
117 {
118  std::unique_lock<std::mutex> readableListLock(m_ReadableMutex);
119  if (!m_ReadableList.empty())
120  {
121  IPacketBufferPtr buffer = std::move(m_ReadableList.front());
122  m_ReadableList.pop();
123  readableListLock.unlock();
124  return buffer;
125  }
126  return nullptr;
127 }
128 
130 {
131  std::unique_lock<std::mutex> availableListLock(m_AvailableMutex, std::defer_lock);
132  packetBuffer->MarkRead();
133  availableListLock.lock();
134  if (m_AvailableList.size() <= m_NumberOfBuffers)
135  {
136  m_AvailableList.push_back(std::move(packetBuffer));
137  }
138  else
139  {
140  // we have been handed a temporary overflow/surge buffer get rid of it
141  packetBuffer->Destroy();
142  if (m_CurrentNumberOfBuffers > m_NumberOfBuffers)
143  {
144  --m_CurrentNumberOfBuffers;
145  }
146  }
147  availableListLock.unlock();
148 }
149 
151 {
152  m_Consumer = consumer;
153 }
154 
156 {
157  // notify consumer that packet is ready to read
158  if (m_Consumer != nullptr)
159  {
160  m_Consumer->SetReadyToRead();
161  }
162 }
163 
164 } // namespace profiling
165 
166 } // namespace armnn
virtual void SetReadyToRead()=0
Set a "ready to read" flag in the buffer to notify the reading thread to start reading it...
void swap(OriginsDescriptor &first, OriginsDescriptor &second)
void SetConsumer(IConsumer *consumer) override
Set Consumer on the buffer manager to be notified when there is a Commit Can only be one consumer...
Copyright (c) 2021 ARM Limited and Contributors.
BufferManager(unsigned int numberOfBuffers=5, unsigned int maxPacketSize=4096)
void FlushReadList() override
Notify the Consumer buffer can be read.
void Commit(IPacketBufferPtr &packetBuffer, unsigned int size, bool notifyConsumer=true) override
IPacketBufferPtr Reserve(unsigned int requestedSize, unsigned int &reservedSize) override
IPacketBufferPtr GetReadableBuffer() override
void MarkRead(IPacketBufferPtr &packetBuffer) override
std::unique_ptr< IPacketBuffer > IPacketBufferPtr
void Release(IPacketBufferPtr &packetBuffer) override