KratosMultiphysics
KRATOS Multiphysics (Kratos) is a framework for building parallel, multi-disciplinary simulation software, aiming at modularity, extensibility, and high performance. Kratos is written in C++, and counts with an extensive Python interface.
chunk.h
Go to the documentation of this file.
1 // | / |
2 // ' / __| _` | __| _ \ __|
3 // . \ | ( | | ( |\__ `
4 // _|\_\_| \__,_|\__|\___/ ____/
5 // Multi-Physics
6 //
7 // License: BSD License
8 // Kratos default license: kratos/license.txt
9 //
10 // Main authors: Pooyan Dadvand
11 //
12 //
13 
14 
15 #if !defined(KRATOS_CHUNK_H_INCLUDED )
16 #define KRATOS_CHUNK_H_INCLUDED
17 
18 // System includes
19 #include <atomic>
20 
21 // External includes
22 
23 // Project includes
24 #include "includes/checks.h"
25 #include "includes/lock_object.h"
26 #include "utilities/openmp_utils.h"
27 
28 namespace Kratos
29 {
32 
35 
37 
44  class Chunk
45  {
46  public:
47 
50 
51  // The reference algorithm uses unsigned char as data type
52  // Here I use std::int64_t to ensure better alignment considering
53  // that objects in Kratos are "always" larger than a double
54  using BlockType = std::int64_t;
55 
56  using SizeType = std::size_t;
57 
58 
62 
64  Chunk() = delete;
65 
67  Chunk(Chunk const& rOther) = delete;
68 
69  Chunk(Chunk&& rOther) = delete;
70 
72  Chunk(std::size_t BlockSizeInBytes, SizeType SizeInBytes) noexcept
73  : mpData(nullptr)
74  , mpEnd(nullptr)
75  , mpUninitializedMemory(nullptr)
76  , mSize(SizeInBytes)
77  , mBlockSizeInBytes(BlockSizeInBytes)
78  , mNumberOfAvailableBlocks(0) // to be initialized in initialize
79  , mFirstAvailableBlock(mpData)
80  , mBlockSizeAfterAlignment((BlockSizeInBytes + sizeof(BlockType) - 1) / sizeof(BlockType)){}
81 
83  ~Chunk() noexcept {
84  delete[] mpData;
85  }
86 
90 
92  Chunk& operator=(Chunk const& rOther) = delete;
93 
97  void Initialize() {
98  const std::size_t data_size = DataSize();
99  mpData = new BlockType[data_size];
100  mpEnd = mpData + data_size;
101  mFirstAvailableBlock = mpData;
102  mNumberOfAvailableBlocks = AllocatableDataSize() / mBlockSizeAfterAlignment;
103  mpUninitializedMemory = mpData;
104 
105 
106  *mpData = 0; // The first entry of the link list to the next one
107  }
108 
110  void* Allocate() {
111  KRATOS_DEBUG_CHECK_NOT_EQUAL(mpData, nullptr);
112 
113  if (IsFull())
114  return nullptr;
115 
116  lock();
117  BlockType * p_result = mFirstAvailableBlock;
118  mFirstAvailableBlock = (p_result >= mpUninitializedMemory) ? mFirstAvailableBlock + mBlockSizeAfterAlignment : (BlockType*)*p_result;
119  // if(p_result >= mpUninitializedMemory) {
120  // mFirstAvailableBlock += mBlockSizeAfterAlignment;
121  // if(mpUninitializedMemory < mpEnd) {
122  // mpUninitializedMemory += mBlockSizeAfterAlignment;
123  // }
124  // }
125  // else{
126  // mFirstAvailableBlock = (BlockType*)*p_result;
127  // }
128 
129  KRATOS_DEBUG_CHECK(Has(p_result));
130 
131  mNumberOfAvailableBlocks--;
132  unlock();
133 
134  mpUninitializedMemory += mBlockSizeAfterAlignment * ((p_result >= mpUninitializedMemory) && (mpUninitializedMemory < mpEnd));
135 
136  return p_result;
137  }
138 
139  void Deallocate(void* pPointrerToRelease) {
140  if (pPointrerToRelease == nullptr)
141  return;
142 
143  KRATOS_DEBUG_CHECK_NOT_EQUAL(mpData, nullptr);
144  // Range check at least in lower bound.
145  KRATOS_DEBUG_CHECK_GREATER_EQUAL(pPointrerToRelease, mpData);
146  BlockType* p_to_release = static_cast<BlockType*>(pPointrerToRelease);
147 
148  // Alignment check
149  KRATOS_DEBUG_CHECK_EQUAL((p_to_release - mpData) % mBlockSizeAfterAlignment, 0);
150 
151  lock();
152  *p_to_release = (BlockType)mFirstAvailableBlock;
153  mFirstAvailableBlock = p_to_release;
154 
155  mNumberOfAvailableBlocks++;
156  unlock();
157  pPointrerToRelease = nullptr;
158 
159  }
160 
161  void Release() {
162  if (mpData == nullptr)
163  return;
164  delete[] mpData;
165  mpData = nullptr;
166  mpEnd = nullptr;
167  mpUninitializedMemory = nullptr;
168 
169  }
170 
171  std::size_t Size() const {
172  return mSize;
173  }
174 
175  std::size_t MemoryUsed() const {
176  if (mpData == nullptr)
177  return sizeof(Chunk);
178  return Size() + sizeof(Chunk);
179  }
180 
181  std::size_t MemoryOverhead() const {
182  if (mpData == nullptr)
183  return sizeof(Chunk);
184  return MemoryUsed() - (mBlockSizeInBytes*(GetNumberOfBlocks() - mNumberOfAvailableBlocks));
185  }
186 
190 
192  return AllocatableDataSize() / mBlockSizeAfterAlignment;
193  }
194 
196  return mNumberOfAvailableBlocks;
197  }
198 
199  const BlockType* pGetData() const {
200  return mpData;
201  }
202 
203  const BlockType* pDataBegin() const {
204  return mpData;
205  }
206 
207  const BlockType* pDataEnd() const {
208  return mpData + DataSize();
209  }
210 
214 
215  bool HasAvailableBlock() const {
216  if (GetNumberOfAvailableBlocks() != 0)
217  return true;
218 
219  return false;
220  }
221 
222  bool Has(const void* pThePointer) const {
223  return ((pThePointer >= mpData) && (pThePointer < mpEnd));
224  }
225 
226  bool IsEmpty() const {
227  return (mNumberOfAvailableBlocks == GetNumberOfBlocks());
228  }
229 
230  bool IsFull() {
231  return (mNumberOfAvailableBlocks == 0);
232  }
233 
234  bool IsInitialized() const {
235  return mpData != nullptr;
236  }
237 
238  bool IsReleased() const {
239  return mpData == nullptr;
240  }
241 
242  void lock(){
243  while(std::atomic_flag_test_and_set_explicit(&mLocked, std::memory_order_acquire))
244  ; // spin until the lock is acquired
245  }
246 
247  void unlock(){
248  std::atomic_flag_clear_explicit(&mLocked, std::memory_order_release);
249  }
250 
254 
256  std::string Info() const {
257  return "Chunk";
258  }
259 
261  void PrintInfo(std::ostream& rOStream) const {
262  rOStream << Info();
263  }
264 
266  void PrintData(std::ostream& rOStream) const {
267  rOStream << " from " << pDataBegin() << " to " << pDataEnd() << " with size " << Size() << " bytes allocated as " << DataSize() << " size_t with " << static_cast<SizeType>(GetNumberOfAvailableBlocks()) << " available blocks" << std::endl;
268  }
269 
271 
272 
273  private:
276 
277  BlockType * mpData;
278  BlockType* mpEnd;
279  BlockType* mpUninitializedMemory;
280  SizeType mSize;
281  SizeType mBlockSizeInBytes;
282  SizeType mNumberOfAvailableBlocks;
283  BlockType* mFirstAvailableBlock;
284  std::atomic_flag mLocked = ATOMIC_FLAG_INIT;
285  const SizeType mBlockSizeAfterAlignment;
286 
290 
291  SizeType GetHeaderSize() const {
292  return 0; // mFirstAvailableBlockIndex
293  }
294 
295  SizeType DataSize() const {
296  return mSize / sizeof(BlockType);
297  }
298 
299  SizeType AllocatableDataSize() const {
300  std::size_t header_size = GetHeaderSize();
301  std::size_t data_size = DataSize();
302  if(data_size > header_size)
303  return data_size - header_size;
304  return 0;
305  }
306 
307  static std::size_t GetBlockSize(std::size_t BlockSizeInBytes) {
308  return (BlockSizeInBytes + sizeof(BlockType) - 1) / sizeof(BlockType);
309  }
310 
312 
313  }; // Class Chunk
314 
318 
319  inline bool operator << (Chunk const& rFirst, Chunk const& rSedond) {
320  return rFirst.pGetData() < rSedond.pGetData();
321  }
322 
324  inline std::ostream& operator << (std::ostream& rOStream,
325  const Chunk& rThis)
326  {
327  rThis.PrintInfo(rOStream);
328  rThis.PrintData(rOStream);
329 
330  return rOStream;
331  }
333 
335 
336 } // namespace Kratos.
337 
338 #endif // KRATOS_CHUNK_H_INCLUDED defined
Chunk is the smallest building block of Kratos memory management.
Definition: chunk.h:45
bool IsFull()
Definition: chunk.h:230
bool IsInitialized() const
Definition: chunk.h:234
void * Allocate()
This function does not throw and returns zero if cannot allocate.
Definition: chunk.h:110
void PrintInfo(std::ostream &rOStream) const
Print information about this object.
Definition: chunk.h:261
Chunk(Chunk &&rOther)=delete
void lock()
Definition: chunk.h:242
~Chunk() noexcept
Destructor is not virtual. This class can not be drived.
Definition: chunk.h:83
std::size_t MemoryOverhead() const
Definition: chunk.h:181
void PrintData(std::ostream &rOStream) const
Print object's data.
Definition: chunk.h:266
SizeType GetNumberOfBlocks() const
Definition: chunk.h:191
bool IsReleased() const
Definition: chunk.h:238
Chunk(std::size_t BlockSizeInBytes, SizeType SizeInBytes) noexcept
The constructor to be called.
Definition: chunk.h:72
std::size_t SizeType
Definition: chunk.h:56
std::size_t MemoryUsed() const
Definition: chunk.h:175
std::string Info() const
Turn back information as a string.
Definition: chunk.h:256
Chunk()=delete
Default constructor is deleted.
bool HasAvailableBlock() const
Definition: chunk.h:215
const BlockType * pGetData() const
Definition: chunk.h:199
Chunk & operator=(Chunk const &rOther)=delete
Assignment operator is deleted.
bool Has(const void *pThePointer) const
Definition: chunk.h:222
void Initialize()
Definition: chunk.h:97
void Release()
Definition: chunk.h:161
const BlockType * pDataBegin() const
Definition: chunk.h:203
Chunk(Chunk const &rOther)=delete
Copy constructor is deleted.
std::size_t Size() const
Definition: chunk.h:171
void Deallocate(void *pPointrerToRelease)
Definition: chunk.h:139
SizeType GetNumberOfAvailableBlocks() const
Definition: chunk.h:195
std::int64_t BlockType
Definition: chunk.h:54
void unlock()
Definition: chunk.h:247
const BlockType * pDataEnd() const
Definition: chunk.h:207
bool IsEmpty() const
Definition: chunk.h:226
#define KRATOS_DEBUG_CHECK_EQUAL(a, b)
Definition: checks.h:217
#define KRATOS_DEBUG_CHECK_NOT_EQUAL(a, b)
Definition: checks.h:218
#define KRATOS_DEBUG_CHECK(IsTrue)
Definition: checks.h:214
#define KRATOS_DEBUG_CHECK_GREATER_EQUAL(a, b)
Definition: checks.h:227
REF: G. R. Cowper, GAUSSIAN QUADRATURE FORMULAS FOR TRIANGLES.
Definition: mesh_condition.cpp:21
std::size_t SizeType
The definition of the size type.
Definition: mortar_classes.h:43
std::ostream & operator<<(std::ostream &rOStream, const LinearMasterSlaveConstraint &rThis)
output stream function
Definition: linear_master_slave_constraint.h:432