xo-alloc: reserve virtual memory, commit pages on demand
This commit is contained in:
parent
a6e4430825
commit
d8b3d7a148
8 changed files with 140 additions and 23 deletions
|
|
@ -8,6 +8,7 @@
|
|||
#include "ObjectStatistics.hpp"
|
||||
#include "xo/indentlog/scope.hpp"
|
||||
#include "xo/indentlog/print/tag.hpp"
|
||||
#include <sys/mman.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace xo {
|
||||
|
|
@ -15,27 +16,52 @@ namespace xo {
|
|||
ArenaAlloc::ArenaAlloc(const std::string & name,
|
||||
std::size_t z, bool debug_flag)
|
||||
{
|
||||
scope log(XO_DEBUG(debug_flag), xtag("name", name));
|
||||
|
||||
this->name_ = name;
|
||||
this->lo_ = (new std::byte [z]);
|
||||
this->checkpoint_ = lo_;
|
||||
this->free_ptr_ = lo_;
|
||||
this->limit_ = lo_ + z;
|
||||
this->hi_ = limit_;
|
||||
this->debug_flag_ = debug_flag;
|
||||
this->page_z_ = getpagesize();
|
||||
|
||||
// reserve virtual memory
|
||||
|
||||
void * base = mmap(nullptr, z, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
// could use this as fallback..
|
||||
//base = (new std::byte [z]);
|
||||
|
||||
if (base == MAP_FAILED) {
|
||||
throw std::runtime_error(tostr("ArenaAlloc: uncommitted allocation failed",
|
||||
xtag("size", z)));
|
||||
}
|
||||
|
||||
this->lo_ = reinterpret_cast<std::byte *>(base);
|
||||
this->committed_z_ = 0;
|
||||
this->checkpoint_ = lo_;
|
||||
this->free_ptr_ = lo_;
|
||||
this->limit_ = lo_ + z;
|
||||
this->hi_ = limit_;
|
||||
this->debug_flag_ = debug_flag;
|
||||
|
||||
if (!lo_) {
|
||||
throw std::runtime_error(tostr("ArenaAlloc: allocation failed",
|
||||
xtag("size", z)));
|
||||
}
|
||||
|
||||
log && log(xtag("lo", (void*)lo_), xtag("page_z", page_z_));
|
||||
}
|
||||
|
||||
ArenaAlloc::~ArenaAlloc()
|
||||
{
|
||||
delete [] this->lo_;
|
||||
|
||||
// hygiene..
|
||||
|
||||
if (lo_) {
|
||||
munmap(lo_, hi_ - lo_);
|
||||
}
|
||||
// could use this as fallback if not using uncommitted technique
|
||||
//delete [] this->lo_;
|
||||
|
||||
this->lo_ = nullptr;
|
||||
this->committed_z_ = 0;
|
||||
this->checkpoint_ = nullptr;
|
||||
this->free_ptr_ = nullptr;
|
||||
this->limit_ = nullptr;
|
||||
|
|
@ -51,6 +77,46 @@ namespace xo {
|
|||
z, debug_flag));
|
||||
}
|
||||
|
||||
namespace {
|
||||
/* alignment better be a power of 2 */
|
||||
std::size_t
|
||||
align_lub(std::size_t x, std::size_t align)
|
||||
{
|
||||
/* e.g:
|
||||
* align = 4096, x%align = 100 -> dx = 3996
|
||||
* align = 4096, x%align = 0 -> dx = 0
|
||||
*/
|
||||
std::size_t dx = (align - (x % align)) % align;
|
||||
|
||||
return x + dx;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ArenaAlloc::expand(size_t offset_z) {
|
||||
scope log(XO_DEBUG(debug_flag_), xtag("offset_z", offset_z), xtag("committed_z", committed_z_));
|
||||
|
||||
if (offset_z <= committed_z_)
|
||||
return true;
|
||||
|
||||
std::size_t align_offset_z = align_lub(offset_z, page_z_);
|
||||
std::byte * commit_start = lo_ + committed_z_;
|
||||
std::size_t new_commit_z = align_offset_z - committed_z_;
|
||||
|
||||
log && log(xtag("align_offset_z", align_offset_z),
|
||||
xtag("new_commit_z", new_commit_z));
|
||||
|
||||
if (mprotect(commit_start, new_commit_z, PROT_READ | PROT_WRITE) != 0) {
|
||||
throw std::runtime_error(tostr("ArenaAlloc::expand: commit failure",
|
||||
xtag("committed_z", committed_z_),
|
||||
xtag("new_commit_z", new_commit_z)));
|
||||
}
|
||||
|
||||
this->committed_z_ = align_offset_z;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ArenaAlloc::set_free_ptr(std::byte * x)
|
||||
{
|
||||
|
|
@ -59,7 +125,7 @@ namespace xo {
|
|||
|
||||
if (lo_ <= x && x < limit_) {
|
||||
this->free_ptr_ = x;
|
||||
if (this->checkpoint_ > free_ptr_)
|
||||
if (checkpoint_ > free_ptr_)
|
||||
this->checkpoint_ = free_ptr_;
|
||||
} else {
|
||||
throw std::runtime_error(tostr("LinearAllog::set_free_ptr(x): expected lo <= x < limit",
|
||||
|
|
@ -128,6 +194,11 @@ namespace xo {
|
|||
return limit_ - lo_;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
ArenaAlloc::committed() const {
|
||||
return committed_z_;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
ArenaAlloc::available() const {
|
||||
return limit_ - free_ptr_;
|
||||
|
|
@ -197,13 +268,15 @@ namespace xo {
|
|||
|
||||
assert(z1 % c_bpw == 0ul);
|
||||
|
||||
this->expand(this->allocated() + z1);
|
||||
|
||||
std::byte * retval = this->free_ptr_;
|
||||
|
||||
log && log(xtag("self", name_), xtag("z0", z0), xtag("+pad", dz), xtag("z1", z1), xtag("avail", this->available()));
|
||||
|
||||
if (free_ptr_ + z1 > limit_) {
|
||||
return nullptr;
|
||||
}
|
||||
log && log(xtag("self", name_),
|
||||
xtag("z0", z0),
|
||||
xtag("+pad", dz),
|
||||
xtag("z1", z1),
|
||||
xtag("avail", this->available()));
|
||||
|
||||
this->free_ptr_ += z1;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue