xo-alloc2: work on fomo Arena

This commit is contained in:
Roland Conybeare 2025-12-11 11:14:46 -05:00
commit a69158ab32
13 changed files with 507 additions and 8 deletions

View file

@ -0,0 +1,91 @@
/** @file AAllocator.hpp
*
* @author Roland Conybeare, Dec 2025
**/
#pragma once
#include "xo/facet/facet_implementation.hpp"
#include "xo/facet/typeseq.hpp"
#include <string>
namespace xo {
namespace mm {
using Copaque = const void *;
using Opaque = void *;
/** Abstract facet for allocation
*
* <----------------------------size-------------------------->
* <------------committed-----------><-------uncommitted------>
* <--allocated-->
*
* XXXXXXXXXXXXXXX___________________..........................
*
* allocated: in use
* committed: physical memory obtained
* uncommitted: mapped in virtual memory, not backed by memory
**/
struct AAllocator {
/** RTTI: unique id# for actual runtime data repr **/
virtual int32_t _typeseq() = 0;
/** optional name for this allocator.
* Labeling, for diagnostics.
**/
virtual const std::string & name(Copaque d) = 0;
/** allocator size in bytes (up to reserved limit)
* includes allocated and uncomitted memory
**/
virtual std::size_t size(Copaque d) = 0;
/** committed size (physical addresses obtained)
**/
virtual std::size_t committed(Copaque d) = 0;
/** true iff pointer @p in range of this allocator
**/
virtual bool contains(Copaque d, const void * p) = 0;
/** allocate @p z bytes of memory. **/
virtual std::byte * alloc(Opaque d, std::size_t z) = 0;
/** reset allocator to empty state **/
virtual void clear(Opaque d) = 0;
/** **/
virtual void destruct_data(Opaque d) = 0;
};
template <typename DRepr>
struct IAllocator_Impl;
template <typename DRepr>
struct IAllocator_Xfer : public AAllocator {
// parallel interface to AAllocator, with specific data type
using Impl = IAllocator_Impl<DRepr>;
static const DRepr & _dcast(Copaque d) { return *(const DRepr *)d; }
// from AAllocator
int32_t _typeseq() override { return s_typeseq; }
const std::string & name(Copaque d) override { return Impl::name(_dcast(d)); }
std::size_t size(Copaque d) override { return Impl::size(*(DRepr*)d); }
std::size_t committed(Copaque d) override { return Impl::committed(*(DRepr*)d); }
bool contains(Copaque d, const void * p) override { return Impl::contains(*(DRepr*)d, p); }
std::byte * alloc(Opaque d, std::size_t z) override { return Impl::alloc(*(DRepr*)d, z); }
void clear(Opaque d) override { return Impl::clear(*(DRepr*)d); }
void destruct_data(Opaque d) override { return Impl::destruct_data(*(DRepr*)d); }
static int32_t s_typeseq;
static bool _valid;
};
template <typename DRepr>
int32_t
IAllocator_Xfer<DRepr>::s_typeseq = facet::typeseq::id<DRepr>();
template <typename DRepr>
bool
IAllocator_Xfer<DRepr>::_valid = facet::valid_facet_implementation<AAllocator, IAllocator_Xfer>();
} /*namespace mm*/
} /*namespace xo*/
/* end AAllocator.hpp */

View file

@ -0,0 +1,82 @@
/** @file DArena.hpp
*
* @author Roland Conybeare, Dec 2025
**/
#pragma once
#include <string>
namespace xo {
namespace mm {
/** ArenaConfig
**/
struct ArenaConfig {
/** optional name, for diagnostics **/
std::string name_;
/** arena size -- hard max = reserved virtual memory **/
std::size_t size_;
/** hugepage size -- using huge pages relieves some TLB pressure
* (provided you use their full extent :)
**/
std::size_t hugepage_z_ = 2 * 1024 * 1024;
/** true to enable debug logging **/
bool debug_flag_ = false;
};
/** Arena allocator state
*
* <----------------------------size-------------------------->
* <------------committed-----------><-------uncommitted------>
* <--allocated-->
*
* XXXXXXXXXXXXXXX___________________..........................
*
* allocated: in use
* committed: physical memory obtained
* uncommitted: mapped in virtual memory, not backed by memory
**/
struct DArena {
/** [lo, hi) already-mapped address range **/
DArena(const ArenaConfig & cfg,
std::byte * lo,
std::byte * hi);
~DArena();
ArenaConfig config_;
/** size of a VM page (via getpagesize()). Likely 4k **/
std::size_t page_z_ = 0;
/** arena owns memory in range [@ref lo_, @ref hi_)
**/
std::byte * lo_ = nullptr;
/** prefix of this size is committed.
* Remainder mapped but uncommitted.
**/
std::size_t committed_z_ = 0;
/** free pointer.
* Memory in range [@ref lo_, @ref free_) current in use
**/
std::byte * free_ = nullptr;
/** soft limit; end of committed virtual memory
* Memory in range [@ref lo_, @ref limit_) is committed
* (backed by physical memory)
**/
std::byte * limit_ = nullptr;
/** hard limit; end of reserved virtual memory
* Memory in range [@ref limit_, @ref hi_) is uncommitted
**/
std::byte * hi_ = nullptr;
};
} /*namespace mm*/
} /*namespace xo*/
/* end DArena.hpp */

View file

@ -0,0 +1,30 @@
/** @file IAllocator_DArena.hpp
*
* @author Roland Conybeare, Dec 2025
**/
#include "AAllocator.hpp"
#include "DArena.hpp"
namespace xo {
namespace mm {
template <>
struct IAllocator_Impl<DArena> {
static const std::string & name(const DArena & s) {
return s.name_;
}
static std::size_t size(const DArena & s);
static std::size_t committed(const DArena & s);
static bool contains(const DArena & s, const void * p);
static std::byte * alloc(const DArena & s, std::size_t z);
static void clear(DArena & s);
static void destruct_data(DArena & s);
};
} /*namespace mm*/
} /*namespace xo*/
/* end IAllocator_DArena.hpp */

View file

@ -0,0 +1,57 @@
/** @file padding.hpp
*
* @author Roland Conybeare, Dec 2025
**/
#pragma once
#include <memory>
#include <cstdint>
namespace xo {
namespace mm {
struct padding {
/** word size for alignment**/
static constexpr std::size_t c_alloc_alignment = sizeof(std::uintptr_t);
/** how much to add to @p z to get a multiple of
* @ref c_alloc_alignment
**/
static inline std::size_t alloc_padding(std::size_t z,
std::size_t align = c_alloc_alignment)
{
/* round up to multiple of c_bpw, but map 0 -> 0
* (table assuming c_bpw==8)
*
* z%c_bpw dz
* ------------
* 0 0
* 1 7
* 2 6
* .. ..
* 7 1
*/
std::size_t dz = (align - (z % align)) % align;
z += dz;
return dz;
}
/** @p z rounded up to an exact multiple
* of @ref c_alloc_alignment
**/
static inline
std::size_t with_padding(std::size_t z,
std::size_t align)
{
return z + alloc_padding(z, align);
}
};
} /*namespace mm*/
} /*namespace xo*/
/* end padding.hpp */