Bläddra i källkod

Added aggregate allocator

devel
Ludovic 'Archivist' Lagouardette 4 år sedan
förälder
incheckning
479f2a65a9
10 ändrade filer med 371 tillägg och 11 borttagningar
  1. +2
    -1
      Makefile
  2. +1
    -1
      include/gp/algorithm/modifiers.hpp
  3. +11
    -0
      include/gp/algorithm/move.hpp
  4. +104
    -0
      include/gp/allocator/aggregator.hpp
  5. +9
    -1
      include/gp/allocator/buddy.hpp
  6. +1
    -0
      include/gp/integer_math.hpp
  7. +142
    -0
      include/gp/ring_list.hpp
  8. +1
    -2
      include/stored_indexed_array.hpp
  9. +100
    -2
      tests/gp_test.cpp
  10. +0
    -4
      tests/test_scaffold.h

+ 2
- 1
Makefile Visa fil

@ -1,5 +1,6 @@
CXX= clang++-8
CXXFLAGS= --std=c++17 -O0 -pthread -DFUZZ_STRENGTH=4000000 \
CXXFLAGS= --std=c++17 -O0 -pthread -DFUZZ_STRENGTH=500000 \
-Wno-unknown-attributes \
-g -fprofile-instr-generate -fcoverage-mapping
all: tests

+ 1
- 1
include/gp/algorithm/modifiers.hpp Visa fil

@ -9,7 +9,7 @@ namespace gp {
template<typename F, typename ... Args>
auto bind_front(F&& func, Args&&... arg_parent)
{
return [&](auto&&... argv){
return [=](auto&&... argv){
return func(arg_parent..., argv...);
};
}

+ 11
- 0
include/gp/algorithm/move.hpp Visa fil

@ -32,6 +32,17 @@ namespace gp{
rhs = tmp;
}
template<typename T>
constexpr void swap(
T&& lhs,
T&& rhs
)
{
auto tmp = lhs;
lhs = rhs;
rhs = tmp;
}
template<typename range_in, typename range_out>
nameless_range<typename range_out::associated_iterator> move(range_in src, range_out dest)
{

+ 104
- 0
include/gp/allocator/aggregator.hpp Visa fil

@ -0,0 +1,104 @@
#pragma once
#include <stddef.h>
#include "gp/ring_list.hpp"
namespace gp {
class aggregator {
struct virtual_allocator
{
virtual ~virtual_allocator() = default;
virtual void* allocate(size_t) = 0;
virtual bool deallocate(void*) = 0;
virtual bool try_reallocate(void*, size_t) = 0;
};
template<typename alloc>
class abstract_allocator final : public virtual_allocator{
alloc internal_representation;
public:
abstract_allocator(abstract_allocator& v)
: internal_representation{v.internal_representation}
{}
abstract_allocator(alloc& v)
: internal_representation{v}
{}
virtual ~abstract_allocator() override = default;
virtual void* allocate(size_t sz) override {
return internal_representation.allocate(sz);
}
virtual bool deallocate(void* ptr) override {
return internal_representation.deallocate(ptr);
}
virtual bool try_reallocate(void* ptr, size_t sz) override {
return internal_representation.try_reallocate(ptr, sz);
}
};
using local_container = ring_list<virtual_allocator, aggregator, false>;
local_container contents;
local_container::explorer mark;
public:
template<typename bootstrapper>
aggregator(bootstrapper&& allocator)
: contents{
new(allocator.allocate(sizeof(local_container::node)))
local_container::node(
new(allocator.allocate(sizeof(bootstrapper))) abstract_allocator(allocator)
),
*this
}
, mark{contents.explore()}
{}
template<typename allocator>
bool insert(allocator&& value) {
return contents.insert<
abstract_allocator<
std::remove_reference_t<
allocator
>
>
>(abstract_allocator(value));
}
void* allocate(size_t sz) {
auto cpy = mark;
do{
if(auto allocated = (*mark).allocate(sz))
{
return allocated;
}
++mark;
}while(cpy != mark);
return nullptr;
}
bool deallocate(void* ptr) {
auto cpy = mark;
do{
if((*cpy).deallocate(ptr))
{
return true;
}
--cpy;
}while(cpy != mark);
return false;
}
bool try_reallocate(void* ptr, size_t sz) {
auto cpy = mark;
do{
if((*cpy).try_reallocate(ptr, sz))
{
return true;
}
--cpy;
}while(cpy != mark);
return false;
}
};
}

+ 9
- 1
include/gp/allocator/buddy.hpp Visa fil

@ -46,6 +46,12 @@ namespace gp{
static constexpr size_t span_size = required_twigs / 4 + (required_twigs % 4 != 0);
gp::array<bundle, span_size> stack;
/**
* This code has been manually hecked and will always return.
* If you find a case where it doesn't, please file an issue.
**/
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreturn-type"
twig get_twig(size_t idx) const {
auto far = idx / 4;
auto local = idx % 4;
@ -60,11 +66,13 @@ namespace gp{
return stack[far].d;
}
}
#pragma clang diagnostic pop
void set_twig(size_t idx, twig v) {
auto far = idx / 4;
auto local = idx % 4;
auto& group = stack[far];
switch(local) {
case 0:
group.a = v;
@ -220,7 +228,7 @@ namespace gp{
}
}
buddy(char* pos,size_t sz)
buddy(char* pos, size_t sz)
: data(pos,pos+sz)
, max_depth(gp::math::msb(sz)-gp::math::msb(align))
, twig_explore_length(1 << max_depth)

+ 1
- 0
include/gp/integer_math.hpp Visa fil

@ -29,6 +29,7 @@ namespace gp {
return MultiplyDeBruijnBitPosition[(uint32_t)(v * 0x07C4ACDDU) >> 27];
}
template<>
constexpr size_t log2<uint64_t>(uint64_t v)
{

+ 142
- 0
include/gp/ring_list.hpp Visa fil

@ -0,0 +1,142 @@
#pragma once
#include <stddef.h>
#include "gp/algorithm/tmp_manip.hpp"
#include "gp/algorithm/modifiers.hpp"
#include "gp_config.hpp"
namespace gp {
template<typename T, typename allocator, bool copy_allocator = true>
class ring_list{
public:
class explorer;
class node {
T* value;
node* prev;
node* next;
public:
node(T* p)
: value{p}
, prev{this}
, next{this}
{}
friend class gp::ring_list<T, allocator, copy_allocator>::explorer;
friend class gp::ring_list<T, allocator, copy_allocator>;
};
class explorer {
node* pos;
public:
explorer(node* v)
: pos{v}
{}
bool operator==(const explorer& oth) const {
return pos == oth.pos;
}
bool operator!=(const explorer& oth) const {
return pos != oth.pos;
}
explorer operator++() {
pos = pos->next;
return pos;
}
explorer operator++(int) {
auto tmp = pos;
pos = pos->next;
return tmp;
}
explorer operator--() {
pos = pos->prev;
return pos;
}
explorer operator--(int) {
auto tmp = pos;
pos = pos->prev;
return tmp;
}
T& operator*() {
return *(pos->value);
}
friend class ring_list;
};
private:
node* any_node;
size_t sz;
typename gp::either<
copy_allocator,
allocator,
gp::reference_wrapper<allocator>
>::type alloc;
void stitch_around(node* n) {
n->prev->next = n->next;
n->next->prev = n->prev;
}
public:
ring_list()
: any_node{nullptr}
, sz{0}
, alloc{}
{}
ring_list(node* initial, allocator& _alloc)
: any_node{initial}
, sz{1}
, alloc{_alloc}
{}
template<typename V = T, typename ...Args>
bool insert(Args&&... elem) {
allocator& used_allocator = alloc;
void* mem = used_allocator.allocate(sizeof(V));
T* p = new(mem) V(elem...);
node* to_insert = nullptr;
if(
nullptr == (to_insert = reinterpret_cast<node*>(used_allocator.allocate(sizeof(node))))
) return false;
to_insert = new(to_insert) node(p);
[[unlikely]] if (any_node == nullptr)
{
any_node = to_insert;
} else {
to_insert->prev = any_node->prev;
to_insert->next = any_node;
to_insert->prev->next = to_insert;
any_node->prev = to_insert;
}
return true;
}
explorer explore() {
return any_node;
}
void remove(explorer& value) {
auto& v = *value;
if(v == explore()) {
if(v->next == v) {
any_node = nullptr;
} else {
stitch_around(any_node);
}
} else {
stitch_around(value.pos);
}
allocator& used_allocator = alloc;
v.value->~T();
gp_config::assertion(used_allocator.deallocate(v.value), "Bad free of value");
value.pos->~node();
gp_config::assertion(used_allocator.deallocate(value.pos), "Bad free of node");
}
};
}

+ 1
- 2
include/stored_indexed_array.hpp Visa fil

@ -1,2 +1 @@
#pragma once
#pragma once

+ 100
- 2
tests/gp_test.cpp Visa fil

@ -1,8 +1,10 @@
#include "test_scaffold.h"
#include "gp/array.hpp"
#include "gp/allocator/aggregator.hpp"
#include "gp/allocator/buddy.hpp"
#include "gp/allocator/dummy.hpp"
#include "gp/algorithm/repeat.hpp"
#include "gp/ring_list.hpp"
#include <thread>
#include <chrono>
#include <set>
@ -12,9 +14,15 @@
#include <random>
#include <iomanip>
#include <iostream>
#include <fstream>
#include <fstream>
#include <algorithm>
#ifndef FUZZ_STRENGTH
#define FUZZ_STRENGTH 2048
#endif
#define MACRO_STRGEN(X) #X
#define MACRO_STR(X) MACRO_STRGEN(X)
@ -331,4 +339,94 @@ struct buddy_fuzz_test : public test_scaffold {
};
append_test dummy_df987sd3(new buddy_fuzz_test{781017366});
append_test dummy_df4sisd3(new buddy_fuzz_test{});
append_test dummy_df4sisd3(new buddy_fuzz_test{});
struct ring_list_test : public test_scaffold {
ring_list_test() {
name = __FILE__ ":5";
}
virtual int run() {
int res = 0;
alignas(8) gp::array<char, 4096> store;
using local_allocator = gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)>;
local_allocator bud{&*store.begin(), store.size()};
{
using string_ring = gp::ring_list<std::string, local_allocator, false>;
auto p = new(bud.allocate(sizeof(std::string))) std::string("Hello");
auto orig = new(bud.allocate(sizeof(string_ring::node))) string_ring::node(p);
string_ring ring{orig, bud};
ring.insert("World");
auto it = ring.explore();
std::string test = "";
do{
test += *it;
++it;
}while(it != ring.explore());
res += (test != "HelloWorld");
}
return res;
}
};
append_test dummy_867fdrgsd3(new ring_list_test{});
struct aggregator_test : public test_scaffold {
aggregator_test() {
name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":6";
rng.seed(seed);
}
std::mt19937 rng{};
int seed = std::random_device{}();
virtual int run() {
int res = 0;
alignas(8) gp::array<char, 4096> store;
using local_allocator = gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)>;
local_allocator bud{&*store.begin(), store.size()};
alignas(8) gp::array<char, 4096> store2;
local_allocator bud2{&*store2.begin(), store2.size()};
gp::aggregator allocator{bud};
allocator.insert(bud2);
{
std::vector<void*> ptr_set;
auto get_random_mem_qt = [&]() -> size_t {
return 1+rng()%(store.size()-1);
};
auto start = std::chrono::steady_clock::now();
{
gp::repeat(FUZZ_STRENGTH, [&](){
void* ptr;
auto sz = get_random_mem_qt();
size_t tries = 0;
std::shuffle(
ptr_set.begin(),
ptr_set.end(),
rng
);
while(!(ptr = allocator.allocate(sz)))
{
void* free_ptr = ptr_set.back();
ptr_set.pop_back();
gp_config::assertion(allocator.deallocate(free_ptr), "could not free sample");
gp_config::assertion(++tries <= store.size(), "infinite fuzzing");
}
ptr_set.emplace_back(ptr);
});
for(auto ptr : ptr_set)
{
bud.deallocate(ptr);
}
ptr_set.resize(0);
}
auto duration = std::chrono::steady_clock::now() - start;
}
return res;
}
};
append_test dummy_8ijfsd658(new aggregator_test{});

+ 0
- 4
tests/test_scaffold.h Visa fil

@ -3,10 +3,6 @@
#include <vector>
#include <memory>
#ifndef FUZZ_STRENGTH
#define FUZZ_STRENGTH = 2048;
#endif
struct test_scaffold{
std::string name;
virtual int run() = 0;

Laddar…
Avbryt
Spara