Commit dfc54dbc authored by BRAMAS Berenger's avatar BRAMAS Berenger

Update alligned memory allocator

parent 55234c38
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define INAMEMORY_HPP #define INAMEMORY_HPP
#include <cstdint> #include <cstdint>
#include <cassert>
/** /**
* Proposes methods to allocate aligned memory. * Proposes methods to allocate aligned memory.
...@@ -14,10 +15,14 @@ ...@@ -14,10 +15,14 @@
* Note: the alignement must be a power of 2 * Note: the alignement must be a power of 2
*/ */
class InaMemory { class InaMemory {
const std::size_t HeaderSize = sizeof(unsigned char*) + sizeof(std::size_t); struct Header{
unsigned char* originPtr;
std::size_t nbElements;
};
const static std::size_t HeaderSize = sizeof(Header);
template < std::size_t Alignement > template < std::size_t Alignement >
static void* Allocate(const std::size_t inSize, const std::size_t inHeader) { static void* Allocate(const std::size_t inSize, const std::size_t inNbelements) {
// Return null for empty allocation // Return null for empty allocation
if (inSize == 0) { if (inSize == 0) {
return nullptr; return nullptr;
...@@ -27,27 +32,20 @@ class InaMemory { ...@@ -27,27 +32,20 @@ class InaMemory {
static_assert(Alignement != 0 && ((Alignement - 1) & Alignement) == 0, "Alignement must be a power of 2"); static_assert(Alignement != 0 && ((Alignement - 1) & Alignement) == 0, "Alignement must be a power of 2");
// We will need to store the adress of the real blocks // We will need to store the adress of the real blocks
const std::size_t Offset = (Alignement < HeaderSize ? HeaderSize / Alignement : 1) * Alignement; const std::size_t Offset = (Alignement < HeaderSize ? (HeaderSize / Alignement) + 1 : 1) * Alignement;
unsigned char* allocatedMemoryPtr = new unsigned char[inSize + Offset - 1]; unsigned char* allocatedMemoryPtr = new unsigned char[inSize + Offset];
unsigned char* alignedMemoryPtr = reinterpret_cast< unsigned char* >((reinterpret_cast< std::size_t >(allocatedMemoryPtr) + Offset - 1) & ~(Alignement - 1)); unsigned char* alignedMemoryPtr = reinterpret_cast< unsigned char* >((reinterpret_cast< std::size_t >(allocatedMemoryPtr) + Offset) & ~(Alignement - 1));
unsigned char* headerPtr = (alignedMemoryPtr - HeaderSize); assert((reinterpret_cast< std::size_t >(alignedMemoryPtr) & (Alignement-1)) == 0);
Header* headerPtr = reinterpret_cast<Header*>(alignedMemoryPtr - HeaderSize);
// Save real address then header value then alignement // Save real address then header value then alignement
*reinterpret_cast< unsigned char** >(headerPtr) = allocatedMemory; headerPtr->originPtr = allocatedMemoryPtr;
*reinterpret_cast< std::size_t* >(headerPtr + sizeof(unsigned char*)) = inHeader; headerPtr->nbElements = inNbelements;
// Return aligned address // Return aligned address
return reinterpret_cast< void* >(alignedMemoryAddress); return reinterpret_cast< void* >(alignedMemoryPtr);
}
static void Release(const void* ptrToFree) {
// If equal to null do nothing
if (ptrToFree) {
// Retrieve real address
const unsigned char* const* storeRealAddress = reinterpret_cast< const unsigned char* const* >(reinterpret_cast< const unsigned char* >(ptrToFree) - HeaderSize);
delete[] reinterpret_cast< const unsigned char* >(*storeRealAddress);
}
} }
public: public:
...@@ -59,24 +57,25 @@ public: ...@@ -59,24 +57,25 @@ public:
const std::size_t sizeInBytes = (inNbElementsInArray * sizeof(ObjectType)); const std::size_t sizeInBytes = (inNbElementsInArray * sizeof(ObjectType));
ObjectType* alignedArray = reinterpret_cast< ObjectType* >(Allocate(sizeInBytes, inNbElementsInArray)); ObjectType* alignedArray = reinterpret_cast< ObjectType* >(Allocate<Alignement>(sizeInBytes, inNbElementsInArray));
for (std::size_t idx = 0; idx < inNbElementsInArray; ++idx) { for (std::size_t idx = 0; idx < inNbElementsInArray; ++idx) {
new (&alignedArray[idx]) ObjectType(); new (&alignedArray[idx]) ObjectType();
} }
return array; return alignedArray;
} }
template < class ObjectType > template < class ObjectType >
inline void _delete(const ObjectType* ptrToFree) { static void _delete(const ObjectType* ptrToFree) {
if (ptrToFree) { if (ptrToFree) {
const std::size_t numberOfElements = (*reinterpret_cast< const std::size_t* >(reinterpret_cast< const unsigned char* >(ptrToFree) + sizeof(unsigned char*) - HeaderSize)); const Header* headerPtr = reinterpret_cast<const Header*>(reinterpret_cast< const unsigned char* >(ptrToFree) - HeaderSize);
const std::size_t numberOfElements = headerPtr->nbElements;
for (std::size_t idx = 0; idx < numberOfElements; ++idx) { for (std::size_t idx = 0; idx < numberOfElements; ++idx) {
ptrToFree[idx].~ObjectType(); ptrToFree[idx].~ObjectType();
} }
Release(ptrToFree); delete[] headerPtr->originPtr;
} }
} }
}; };
......
///////////////////////////////////////////////////////////////////////////
// Inastemp - Berenger Bramas MPCDF - 2016
// Under MIT Licence, please you must read the LICENCE file.
///////////////////////////////////////////////////////////////////////////
#include "InastempGlobal.h"
#include "Common/InaMemory.hpp"
#include "UTester.hpp"
#include <cmath>
#include <cstring>
#include <vector>
class TestMemo : public UTester< TestMemo > {
using Parent = UTester< TestMemo >;
template <long int alignement>
void TestBasic() {
{
}
for(long int size = 1 ; size < 10 ; ++size){
{
char* vecChar = InaMemory::_new<alignement, char>(size);
UASSERTETRUE(vecChar != nullptr);
UASSERTETRUE((reinterpret_cast<unsigned long>(vecChar) & (alignement-1)) == 0);
InaMemory::_delete(vecChar);
}
{
double* vecDouble = InaMemory::_new<alignement, double>(size);
UASSERTETRUE(vecDouble != nullptr);
UASSERTETRUE((reinterpret_cast<unsigned long>(vecDouble) & (alignement-1)) == 0);
InaMemory::_delete(vecDouble);
}
{
std::vector<double>* vecDouble = InaMemory::_new<alignement, std::vector<double> >(size);
UASSERTETRUE(vecDouble != nullptr);
UASSERTETRUE((reinterpret_cast<unsigned long>(vecDouble) & (alignement-1)) == 0);
InaMemory::_delete(vecDouble);
}
}
}
void SetTests() {
Parent::AddTest(&TestMemo::TestBasic<1>, "Basic memo test 1");
Parent::AddTest(&TestMemo::TestBasic<2>, "Basic memo test 2");
Parent::AddTest(&TestMemo::TestBasic<4>, "Basic memo test 4");
Parent::AddTest(&TestMemo::TestBasic<8>, "Basic memo test 8");
Parent::AddTest(&TestMemo::TestBasic<16>, "Basic memo test 16");
Parent::AddTest(&TestMemo::TestBasic<32>, "Basic memo test 32");
}
};
int main() {
return TestMemo().Run();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment