git.s-ol.nu ~forks/DiligentCore / 3638b2e
Fixed issues with alignment in linear allocator assiduous 11 months ago
2 changed file(s) with 110 addition(s) and 109 deletion(s). Raw diff Collapse all Expand all
5555
5656 LinearAllocator(LinearAllocator&& Other) :
5757 // clang-format off
58 m_pDataStart {Other.m_pDataStart},
59 m_pCurrPtr {Other.m_pCurrPtr },
60 m_pDataEnd {Other.m_pDataEnd },
61 m_pAllocator {Other.m_pAllocator}
58 m_pDataStart {Other.m_pDataStart },
59 m_pCurrPtr {Other.m_pCurrPtr },
60 m_ReservedSize {Other.m_ReservedSize },
61 m_CurrAlignment{Other.m_CurrAlignment},
62 m_pAllocator {Other.m_pAllocator }
6263 // clang-format on
6364 {
64 Other.m_pDataStart = nullptr;
65 Other.m_pCurrPtr = nullptr;
66 Other.m_pDataEnd = nullptr;
67 Other.m_pAllocator = nullptr;
65 Other.Reset();
6866 }
6967
7068 ~LinearAllocator()
7472
7573 void Free()
7674 {
77 if (m_pDataStart != nullptr && m_pDataStart != GetDummyMemory() && m_pAllocator != nullptr)
75 if (m_pDataStart != nullptr && m_pAllocator != nullptr)
7876 {
7977 m_pAllocator->Free(m_pDataStart);
8078 }
81
82 m_pDataStart = nullptr;
83 m_pCurrPtr = nullptr;
84 m_pDataEnd = nullptr;
85 m_pAllocator = nullptr;
79 Reset();
8680 }
8781
8882 void* Release()
8983 {
90 void* Ptr = m_pDataStart;
91 m_pDataStart = nullptr;
92 m_pCurrPtr = nullptr;
93 m_pDataEnd = nullptr;
94 m_pAllocator = nullptr;
84 void* Ptr = m_pDataStart;
85 Reset();
9586 return Ptr;
9687 }
9788
98 void AddSpace(size_t size, size_t align)
99 {
100 VERIFY(m_pDataStart == nullptr || m_pDataStart == GetDummyMemory(), "Memory has already been allocated");
101 AllocateInternal(size, align);
89 void AddSpace(size_t size, size_t alignment)
90 {
91 VERIFY(m_pDataStart == nullptr, "Memory has already been allocated");
92 VERIFY(IsPowerOfTwo(alignment), "Alignment is not a power of two!");
93
94 if (size == 0)
95 return;
96
97 if (m_CurrAlignment == 0)
98 {
99 VERIFY(m_ReservedSize == 0, "This is expected to be a very first time the space is added");
100 m_CurrAlignment = sizeof(void*);
101 }
102
103 if (alignment > m_CurrAlignment)
104 {
105 // Reserve extra space that may be needed for alignment
106 m_ReservedSize += alignment - m_CurrAlignment;
107 }
108 m_CurrAlignment = alignment;
109
110 size = Align(size, alignment);
111 m_ReservedSize += size;
112
113 #if DILIGENT_DEBUG
114 m_DbgAllocations.emplace_back(size, alignment, m_ReservedSize);
115 #endif
102116 }
103117
104118 template <typename T>
120134
121135 void Reserve(size_t size)
122136 {
123 VERIFY(m_pDataStart == nullptr || m_pDataStart == GetDummyMemory(), "Memory has already been allocated");
124 VERIFY(m_pCurrPtr == nullptr, "Space has been added to the allocator and will be overriden");
125 m_pCurrPtr = m_pDataStart + size;
137 VERIFY(m_pDataStart == nullptr, "Memory has already been allocated");
138 VERIFY(m_ReservedSize == 0, "Space has been added to the allocator and will be overriden");
139 m_ReservedSize = size;
126140 Reserve();
127141 }
128142
129143 void Reserve()
130144 {
131 VERIFY(m_pDataStart == nullptr || m_pDataStart == GetDummyMemory(), "Memory has already been allocated");
145 VERIFY(m_pDataStart == nullptr, "Memory has already been allocated");
132146 VERIFY(m_pAllocator != nullptr, "Allocator must not be null");
133147 // Make sure the data size is at least sizeof(void*)-aligned
134 auto DataSize = Align(static_cast<size_t>(m_pCurrPtr - m_pDataStart), sizeof(void*));
135 if (DataSize > 0)
136 {
137 m_pDataStart = reinterpret_cast<uint8_t*>(m_pAllocator->Allocate(DataSize, "Raw memory for linear allocator", __FILE__, __LINE__));
148 m_ReservedSize = Align(m_ReservedSize, sizeof(void*));
149 if (m_ReservedSize > 0)
150 {
151 m_pDataStart = reinterpret_cast<uint8_t*>(m_pAllocator->Allocate(m_ReservedSize, "Raw memory for linear allocator", __FILE__, __LINE__));
138152 VERIFY(m_pDataStart == Align(m_pDataStart, sizeof(void*)), "Memory pointer must be at least sizeof(void*)-aligned");
139153
140154 m_pCurrPtr = m_pDataStart;
141 m_pDataEnd = m_pDataStart + DataSize;
142 }
143 }
144
145 void* Allocate(size_t size, size_t align)
146 {
155 }
156 m_CurrAlignment = sizeof(void*);
157 }
158
159 void* Allocate(size_t size, size_t alignment)
160 {
161 VERIFY(size == 0 || m_pDataStart != nullptr, "Memory has not been allocated");
162 VERIFY(IsPowerOfTwo(alignment), "Alignment is not a power of two!");
163
147164 if (size == 0)
148165 return nullptr;
149166
150 VERIFY(m_pDataStart != nullptr && m_pDataStart != GetDummyMemory(), "Memory has not been allocated");
151 return AllocateInternal(size, align);
167 size = Align(size, alignment);
168
169 #if DILIGENT_DEBUG
170 VERIFY(m_DbgCurrAllocation < m_DbgAllocations.size(), "Allocation number exceed the number of allocations that were originally reserved.");
171 const auto& CurrAllocation = m_DbgAllocations[m_DbgCurrAllocation++];
172 VERIFY(CurrAllocation.size == size, "Allocation size (", size, ") does not match the initially requested size (", CurrAllocation.size, ")");
173 VERIFY(CurrAllocation.alignment == alignment, "Allocation alignment (", alignment, ") does not match the initially requested alignment (", CurrAllocation.alignment, ")");
174 #endif
175
176 VERIFY(Align(m_pCurrPtr, m_CurrAlignment) == m_pCurrPtr, "Current pointer is not aligned as expected");
177 m_pCurrPtr = Align(m_pCurrPtr, alignment);
178 m_CurrAlignment = alignment;
179
180 VERIFY(m_pCurrPtr + size <= m_pDataStart + CurrAllocation.reserved_size,
181 "Allocation size exceeds the initially reserved space. This is likely a bug.");
182
183 auto* ptr = m_pCurrPtr;
184 m_pCurrPtr += size;
185
186 VERIFY(m_pCurrPtr <= m_pDataStart + m_ReservedSize, "Allocation size exceeds the reserved space");
187
188 return ptr;
152189 }
153190
154191 template <typename T>
198235 if (Str == nullptr)
199236 return nullptr;
200237
201 auto* Ptr = reinterpret_cast<Char*>(AllocateInternal(strlen(Str) + 1, 1));
238 auto* Ptr = reinterpret_cast<Char*>(Allocate(strlen(Str) + 1, 1));
202239 Char* Dst = Ptr;
203 while (*Str != 0 && Dst < reinterpret_cast<Char*>(m_pDataEnd))
240
241 const auto* pDataEnd = reinterpret_cast<Char*>(m_pDataStart) + m_ReservedSize;
242 while (*Str != 0 && Dst < pDataEnd)
204243 {
205244 *(Dst++) = *(Str++);
206245 }
207 if (Dst < reinterpret_cast<Char*>(m_pDataEnd))
246 if (Dst < pDataEnd)
208247 *(Dst++) = 0;
209248 else
210249 UNEXPECTED("Not enough space reserved for the string");
250
211251 VERIFY_EXPR(reinterpret_cast<Char*>(m_pCurrPtr) == Dst);
212252 return Ptr;
213253 }
224264
225265 size_t GetReservedSize() const
226266 {
227 return static_cast<size_t>(m_pDataEnd - m_pDataStart);
267 return m_ReservedSize;
228268 }
229269
230270 private:
231 void* AllocateInternal(size_t size, size_t align)
232 {
233 VERIFY(IsPowerOfTwo(align), "Alignment is not a power of two!");
234 if (size == 0)
235 return m_pCurrPtr;
236
237 if (m_pCurrPtr == nullptr)
238 {
239 VERIFY_EXPR(m_pDataStart == nullptr);
240 m_pDataStart = m_pCurrPtr = GetDummyMemory();
241 }
242
243 m_pCurrPtr = Align(m_pCurrPtr, align);
244 auto* ptr = m_pCurrPtr;
245
246 #if DILIGENT_DEBUG
247 if (m_pDataStart == GetDummyMemory())
248 {
249 m_DbgAllocations.emplace_back(size, align, m_pCurrPtr - m_pDataStart);
250 }
251 else
252 {
253 VERIFY(m_DbgCurrAllocation < m_DbgAllocations.size(), "Allocation number exceed the number of allocations that were originally reserved.");
254 const auto& CurrAllocation = m_DbgAllocations[m_DbgCurrAllocation++];
255 VERIFY(CurrAllocation.size == size, "Allocation size (", size, ") does not match the initially requested size (", CurrAllocation.size, ")");
256 VERIFY(CurrAllocation.alignment == align, "Allocation alignment (", align, ") does not match initially requested alignment (", CurrAllocation.alignment, ")");
257
258 auto CurrOffset = m_pCurrPtr - m_pDataStart;
259 VERIFY(CurrOffset <= CurrAllocation.offset,
260 "Allocation offset exceed the offset that was initially computed. "
261 "This should never happen as long as the allocated memory is sizeof(void*)-aligned.");
262 }
263 #endif
264
265 m_pCurrPtr += size;
266
267 VERIFY(m_pDataEnd == nullptr || m_pCurrPtr <= m_pDataEnd, "Allocation size exceeds the reserved space");
268
269 return ptr;
270 }
271
272 static uint8_t* GetDummyMemory()
273 {
274 // Simulate that allocated memory is only sizeof(void*)-aligned
275 auto* DummyMemory = reinterpret_cast<uint8_t*>(sizeof(void*));
276 VERIFY_EXPR(DummyMemory != nullptr);
277 return DummyMemory;
278 }
279
280 uint8_t* m_pDataStart = nullptr;
281 uint8_t* m_pCurrPtr = nullptr;
282 uint8_t* m_pDataEnd = nullptr;
283 IMemoryAllocator* m_pAllocator = nullptr;
271 void Reset()
272 {
273 m_pDataStart = nullptr;
274 m_pCurrPtr = nullptr;
275 m_ReservedSize = 0;
276 m_CurrAlignment = 0;
277 m_pAllocator = nullptr;
278 }
279
280 uint8_t* m_pDataStart = nullptr;
281 uint8_t* m_pCurrPtr = nullptr;
282 size_t m_ReservedSize = 0;
283 size_t m_CurrAlignment = 0;
284 IMemoryAllocator* m_pAllocator = nullptr;
284285
285286 #if DILIGENT_DEBUG
286287 size_t m_DbgCurrAllocation = 0;
287288 struct DbgAllocationInfo
288289 {
289 const size_t size;
290 const size_t alignment;
291 const ptrdiff_t offset;
292
293 DbgAllocationInfo(size_t _size, size_t _alignment, ptrdiff_t _offset) :
290 const size_t size;
291 const size_t alignment;
292 const size_t reserved_size;
293
294 DbgAllocationInfo(size_t _size, size_t _alignment, size_t _reserved_size) :
294295 size{_size},
295296 alignment{_alignment},
296 offset{_offset}
297 reserved_size{_reserved_size}
297298 {
298299 }
299300 };
153153 const std::string SrcStr = "123456789";
154154
155155 Allocator.AddSpace<uint8_t>();
156 EXPECT_EQ(Allocator.GetCurrentSize(), size_t{1});
156 EXPECT_EQ(Allocator.GetReservedSize(), size_t{1});
157157 Allocator.AddSpace<uint16_t>();
158 EXPECT_EQ(Allocator.GetCurrentSize(), size_t{1 + 1 + 2});
158 EXPECT_EQ(Allocator.GetReservedSize(), size_t{1 + 1 + 2});
159159 Allocator.AddSpace(0, 16);
160 EXPECT_EQ(Allocator.GetCurrentSize(), size_t{4});
160 EXPECT_EQ(Allocator.GetReservedSize(), size_t{4});
161161 Allocator.AddSpaceForString(SrcStr);
162 EXPECT_EQ(Allocator.GetCurrentSize(), size_t{4 + 10});
162 EXPECT_EQ(Allocator.GetReservedSize(), size_t{4 + 10});
163163 Allocator.AddSpace<uint32_t>(5);
164 EXPECT_EQ(Allocator.GetCurrentSize(), size_t{14 + 2 + 5 * 4});
164 EXPECT_EQ(Allocator.GetReservedSize(), size_t{14 + 3 + 5 * 4});
165165 Allocator.AddSpace<uint64_t>(3);
166 EXPECT_EQ(Allocator.GetCurrentSize(), size_t{36 + 4 + 3 * 8});
166 EXPECT_EQ(Allocator.GetReservedSize(), size_t{37 + 4 + 3 * 8});
167167 Allocator.AddSpace(0, 16);
168 EXPECT_EQ(Allocator.GetCurrentSize(), size_t{64});
168 EXPECT_EQ(Allocator.GetReservedSize(), size_t{65});
169169 Allocator.AddSpace<TObj1k>(4);
170170
171171 Allocator.Reserve();