Commit | Line | Data |
---|---|---|
1103eb60 | 1 | // Copyright (c) 2002-2023 OPEN CASCADE SAS |
b311480e | 2 | // |
973c2be1 | 3 | // This file is part of Open CASCADE Technology software library. |
b311480e | 4 | // |
d5f74e42 | 5 | // This library is free software; you can redistribute it and/or modify it under |
6 | // the terms of the GNU Lesser General Public License version 2.1 as published | |
973c2be1 | 7 | // by the Free Software Foundation, with special exception defined in the file |
8 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT | |
9 | // distribution for complete text of the license and disclaimer of any warranty. | |
b311480e | 10 | // |
973c2be1 | 11 | // Alternatively, this file may be used under the terms of Open CASCADE |
12 | // commercial license or contractual agreement. | |
b311480e | 13 | |
7fd59977 | 14 | #include <NCollection_IncAllocator.hxx> |
1103eb60 | 15 | |
23be7421 | 16 | #include <Standard_Mutex.hxx> |
7fd59977 | 17 | #include <Standard_OutOfMemory.hxx> |
7fd59977 | 18 | |
1103eb60 | 19 | #include <cmath> |
7fd59977 | 20 | |
1103eb60 | 21 | IMPLEMENT_STANDARD_RTTIEXT(NCollection_IncAllocator, NCollection_BaseAllocator) |
92efcf78 | 22 | |
c99551fa K |
23 | namespace |
24 | { | |
1103eb60 | 25 | // Bounds for checking block size level |
26 | static constexpr unsigned THE_SMALL_BOUND_BLOCK_SIZE = NCollection_IncAllocator::THE_DEFAULT_BLOCK_SIZE * 16; // 196 KB | |
27 | static constexpr unsigned THE_MEDIUM_BOUND_BLOCK_SIZE = NCollection_IncAllocator::THE_DEFAULT_BLOCK_SIZE * 64; // 786 KB | |
28 | static constexpr unsigned THE_LARGE_BOUND_BLOCK_SIZE = NCollection_IncAllocator::THE_DEFAULT_BLOCK_SIZE * 1024; // 12 MB | |
29 | ||
30 | //======================================================================= | |
31 | //function : computeLevel | |
32 | //purpose : | |
33 | //======================================================================= | |
34 | NCollection_IncAllocator::IBlockSizeLevel computeLevel(const unsigned int theSize) | |
c99551fa | 35 | { |
1103eb60 | 36 | if (theSize < NCollection_IncAllocator::THE_DEFAULT_BLOCK_SIZE) |
37 | { | |
38 | return NCollection_IncAllocator::IBlockSizeLevel::Min; | |
39 | } | |
40 | else if (theSize < THE_SMALL_BOUND_BLOCK_SIZE) | |
41 | { | |
42 | return NCollection_IncAllocator::IBlockSizeLevel::Small; | |
43 | } | |
44 | else if (theSize < THE_MEDIUM_BOUND_BLOCK_SIZE) | |
45 | { | |
46 | return NCollection_IncAllocator::IBlockSizeLevel::Medium; | |
47 | } | |
48 | else if (theSize < THE_LARGE_BOUND_BLOCK_SIZE) | |
49 | { | |
50 | return NCollection_IncAllocator::IBlockSizeLevel::Large; | |
51 | } | |
52 | else | |
53 | { | |
54 | return NCollection_IncAllocator::IBlockSizeLevel::Max; | |
55 | } | |
c99551fa | 56 | } |
23be7421 M |
57 | } |
58 | ||
59 | //======================================================================= | |
1103eb60 | 60 | //function : NCollection_IncAllocator |
61 | //purpose : Constructor | |
23be7421 | 62 | //======================================================================= |
1103eb60 | 63 | NCollection_IncAllocator::NCollection_IncAllocator(const size_t theDefaultSize) : |
64 | myBlockSize(static_cast<unsigned>(theDefaultSize < THE_MINIMUM_BLOCK_SIZE ? THE_DEFAULT_BLOCK_SIZE : theDefaultSize)) | |
65 | {} | |
302f96fb | 66 | |
23be7421 | 67 | //======================================================================= |
1103eb60 | 68 | //function : SetThreadSafe |
69 | //purpose : Constructor | |
23be7421 | 70 | //======================================================================= |
1103eb60 | 71 | void NCollection_IncAllocator::SetThreadSafe (const bool theIsThreadSafe) |
23be7421 | 72 | { |
1103eb60 | 73 | if(theIsThreadSafe) |
64531d9c | 74 | { |
1103eb60 | 75 | if (!myMutex) |
76 | { | |
77 | myMutex = new Standard_Mutex; | |
78 | } | |
64531d9c | 79 | } |
1103eb60 | 80 | else |
23be7421 | 81 | { |
1103eb60 | 82 | delete myMutex; |
83 | myMutex = nullptr; | |
23be7421 | 84 | } |
7fd59977 | 85 | } |
86 | ||
87 | //======================================================================= | |
88 | //function : ~NCollection_IncAllocator | |
89 | //purpose : Destructor | |
90 | //======================================================================= | |
1103eb60 | 91 | NCollection_IncAllocator::~NCollection_IncAllocator() |
7fd59977 | 92 | { |
1103eb60 | 93 | clean(); |
95c882e9 | 94 | delete myMutex; |
7fd59977 | 95 | } |
96 | ||
95c882e9 | 97 | //======================================================================= |
1103eb60 | 98 | //function : AllocateOptimal |
99 | //purpose : allocate a memory | |
95c882e9 | 100 | //======================================================================= |
1103eb60 | 101 | void* NCollection_IncAllocator::AllocateOptimal(const size_t theSize) |
95c882e9 | 102 | { |
1103eb60 | 103 | Standard_Mutex::Sentry aLock(myMutex); |
104 | // Allocating using general block | |
105 | IBlock* aBlock = nullptr; | |
106 | // Use allocated blocks | |
107 | if (myAllocationHeap && myAllocationHeap->AvailableSize >= theSize) | |
95c882e9 | 108 | { |
1103eb60 | 109 | aBlock = myAllocationHeap; |
95c882e9 | 110 | } |
1103eb60 | 111 | else // Allocate new general block |
95c882e9 | 112 | { |
1103eb60 | 113 | if (++myBlockCount % 5 == 0) // increase count before checking |
114 | { | |
115 | increaseBlockSize(); | |
116 | } | |
117 | if (myBlockSize < theSize) | |
118 | { | |
119 | myBlockSize = static_cast<unsigned>(theSize); | |
120 | } | |
121 | void* aBufferBlock = Standard::AllocateOptimal(myBlockSize + sizeof(IBlock)); | |
122 | aBlock = new (aBufferBlock) IBlock(aBufferBlock, myBlockSize); | |
123 | aBlock->NextBlock = myAllocationHeap; | |
124 | aBlock->NextOrderedBlock = myOrderedBlocks; | |
125 | myOrderedBlocks = aBlock; | |
126 | myAllocationHeap = aBlock; | |
95c882e9 | 127 | } |
1103eb60 | 128 | void* aRes = aBlock->CurPointer; |
129 | aBlock->CurPointer += theSize; | |
130 | aBlock->AvailableSize -= theSize; | |
131 | if (aBlock->AvailableSize < 16) | |
132 | { | |
133 | myAllocationHeap = aBlock->NextBlock; | |
134 | aBlock->NextBlock = myUsedHeap; | |
135 | myUsedHeap = aBlock; | |
136 | } | |
137 | else | |
138 | { | |
139 | IBlock* aBlockIter = aBlock->NextBlock; | |
140 | IBlock* aBlockToReplaceAfter = nullptr; | |
141 | while (aBlockIter) // Search new sorted position | |
142 | { | |
143 | if (aBlockIter->AvailableSize > aBlock->AvailableSize) | |
144 | { | |
145 | aBlockToReplaceAfter = aBlockIter; | |
146 | aBlockIter = aBlockIter->NextBlock; | |
147 | continue; | |
148 | } | |
149 | break; | |
150 | } | |
151 | if (aBlockToReplaceAfter) // Update list order | |
152 | { | |
153 | IBlock* aNext = aBlockToReplaceAfter->NextBlock; | |
154 | aBlockToReplaceAfter->NextBlock = aBlock; | |
155 | myAllocationHeap = aBlock->NextBlock; | |
156 | aBlock->NextBlock = aNext; | |
157 | } | |
158 | } | |
159 | return aRes; | |
95c882e9 | 160 | } |
161 | ||
7fd59977 | 162 | //======================================================================= |
163 | //function : Allocate | |
1103eb60 | 164 | //purpose : Allocate a memory |
7fd59977 | 165 | //======================================================================= |
1103eb60 | 166 | void* NCollection_IncAllocator::Allocate(const size_t theSize) |
7fd59977 | 167 | { |
1103eb60 | 168 | return AllocateOptimal(theSize); |
7fd59977 | 169 | } |
170 | ||
171 | //======================================================================= | |
1103eb60 | 172 | //function : clean |
7fd59977 | 173 | //purpose : |
174 | //======================================================================= | |
1103eb60 | 175 | void NCollection_IncAllocator::clean() |
7fd59977 | 176 | { |
1103eb60 | 177 | Standard_Mutex::Sentry aLock(myMutex); |
178 | IBlock* aHeapIter = myOrderedBlocks; | |
179 | while (aHeapIter) | |
db56cc2d | 180 | { |
1103eb60 | 181 | IBlock* aCur = aHeapIter; |
182 | aHeapIter = aHeapIter->NextOrderedBlock; | |
183 | Standard::Free(aCur); | |
db56cc2d | 184 | } |
1103eb60 | 185 | myOrderedBlocks = nullptr; |
186 | myAllocationHeap = nullptr; | |
187 | myUsedHeap = nullptr; | |
188 | myBlockCount = 0; | |
189 | myBlockSize = THE_DEFAULT_BLOCK_SIZE; | |
7fd59977 | 190 | } |
191 | ||
192 | //======================================================================= | |
1103eb60 | 193 | //function : increaseBlockSize |
7fd59977 | 194 | //purpose : |
195 | //======================================================================= | |
1103eb60 | 196 | void NCollection_IncAllocator::increaseBlockSize() |
7fd59977 | 197 | { |
1103eb60 | 198 | switch (computeLevel(myBlockSize)) |
199 | { | |
200 | case NCollection_IncAllocator::IBlockSizeLevel::Min: | |
201 | myBlockSize *= 8; | |
202 | break; | |
203 | case NCollection_IncAllocator::IBlockSizeLevel::Small: | |
204 | myBlockSize *= 4; | |
205 | break; | |
206 | case NCollection_IncAllocator::IBlockSizeLevel::Medium: | |
207 | myBlockSize *= 2; | |
208 | break; | |
209 | case NCollection_IncAllocator::IBlockSizeLevel::Large: | |
210 | myBlockSize = static_cast<unsigned>(std::lround(myBlockSize * 1.5)); | |
211 | break; | |
212 | case NCollection_IncAllocator::IBlockSizeLevel::Max: | |
213 | break; | |
7fd59977 | 214 | } |
215 | } | |
216 | ||
217 | //======================================================================= | |
1103eb60 | 218 | //function : resetBlock |
7fd59977 | 219 | //purpose : |
220 | //======================================================================= | |
1103eb60 | 221 | void NCollection_IncAllocator::resetBlock(IBlock* theBlock) const |
7fd59977 | 222 | { |
1103eb60 | 223 | theBlock->AvailableSize = theBlock->AvailableSize + (theBlock->CurPointer - (reinterpret_cast<char*>(theBlock) + sizeof(IBlock))); |
224 | theBlock->CurPointer = reinterpret_cast<char*>(theBlock) + sizeof(IBlock); | |
7fd59977 | 225 | } |
226 | ||
227 | //======================================================================= | |
1103eb60 | 228 | //function : Reset |
229 | //purpose : | |
7fd59977 | 230 | //======================================================================= |
1103eb60 | 231 | void NCollection_IncAllocator::Reset(const Standard_Boolean theReleaseMemory) |
7fd59977 | 232 | { |
1103eb60 | 233 | if (theReleaseMemory) |
234 | { | |
235 | clean(); | |
236 | return; | |
237 | } | |
238 | Standard_Mutex::Sentry aLock(myMutex); | |
239 | IBlock* aHeapIter = myOrderedBlocks; | |
240 | while (aHeapIter) | |
241 | { | |
242 | IBlock* aCur = aHeapIter; | |
243 | aHeapIter = aHeapIter->NextOrderedBlock; | |
244 | aCur->NextBlock = aHeapIter; | |
245 | resetBlock(aCur); // reset size and pointer | |
246 | } | |
247 | myAllocationHeap = myOrderedBlocks; | |
248 | myUsedHeap = nullptr; | |
7fd59977 | 249 | } |
250 | ||
251 | //======================================================================= | |
1103eb60 | 252 | //function : IBlockSmall::IBlockSmall |
7fd59977 | 253 | //purpose : |
254 | //======================================================================= | |
1103eb60 | 255 | NCollection_IncAllocator::IBlock::IBlock(void* thePointer, |
256 | const size_t theSize) : | |
257 | CurPointer(static_cast<char*>(thePointer) + sizeof(IBlock)), | |
258 | AvailableSize(theSize) | |
259 | {} |