genode/repos/os/src/test/slab/main.cc

164 lines
3.7 KiB
C++

/*
* \brief Slab allocator test
* \author Norman Feske
* \date 2015-03-31
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <base/component.h>
#include <base/heap.h>
#include <base/slab.h>
#include <base/log.h>
#include <timer_session/connection.h>
using Genode::size_t;
using Genode::log;
using Genode::error;
struct Array_of_slab_elements
{
Genode::Slab & slab;
Genode::Allocator & alloc;
size_t const num_elem;
size_t const slab_size;
void **elem;
/**
* Return size of 'elem' array in bytes
*/
size_t _elem_array_size() const { return num_elem*sizeof(void *); }
struct Alloc_failed { };
Array_of_slab_elements(Genode::Slab &slab, size_t num_elem, size_t slab_size,
Genode::Allocator & alloc)
: slab(slab), alloc(alloc), num_elem(num_elem), slab_size(slab_size),
elem((void**) alloc.alloc(_elem_array_size()))
{
log(" allocate ", num_elem, " elements");
for (size_t i = 0; i < num_elem; i++)
if (!slab.alloc(slab_size, &elem[i])) throw Alloc_failed();
}
~Array_of_slab_elements()
{
log(" free ", num_elem, " elements");
for (size_t i = 0; i < num_elem; i++)
slab.free(elem[i], slab_size);
alloc.free(elem, _elem_array_size());
}
private:
/*
* Noncopyable
*/
Array_of_slab_elements(Array_of_slab_elements const &);
Array_of_slab_elements &operator = (Array_of_slab_elements const &);
};
void Component::construct(Genode::Env & env)
{
static Genode::Heap heap(env.ram(), env.rm());
log("--- slab test ---");
static Timer::Connection timer(env);
enum { SLAB_SIZE = 16, BLOCK_SIZE = 256 };
struct Tracked_alloc : Genode::Allocator
{
size_t _consumed = 0;
Allocator &_alloc;
bool alloc(size_t size, void **out_addr) override
{
if (_alloc.alloc(size, out_addr)) {
_consumed += size;
return true;
}
return false;
}
void free(void *addr, size_t size) override
{
_alloc.free(addr, size);
_consumed -= size;
}
size_t overhead(size_t) const override { return 0; }
size_t consumed() const override { return _consumed; }
bool need_size_for_free() const override { return true; }
Tracked_alloc(Allocator &alloc) : _alloc(alloc) { }
};
Tracked_alloc alloc { heap };
{
Genode::Slab slab(SLAB_SIZE, BLOCK_SIZE, nullptr, &alloc);
for (unsigned i = 1; i <= 10; i++) {
log("round ", i, " ("
"used quota: ", alloc.consumed(), " "
"time: ", timer.elapsed_ms(), " ms)");
Array_of_slab_elements array(slab, i*100000, SLAB_SIZE, heap);
log(" allocation completed (used quota: ", alloc.consumed(), ")");
}
log(" finished (used quota: ", alloc.consumed(), ", "
"time: ", timer.elapsed_ms(), " ms)");
/*
* The slab keeps two empty blocks around. For the test, we also need to
* take the overhead of the two block allocations at the heap into
* account.
*/
enum { HEAP_OVERHEAD = 9*sizeof(long) };
if (alloc.consumed() > 2*(BLOCK_SIZE + HEAP_OVERHEAD)) {
error("slab failed to release empty slab blocks");
return;
}
}
/* validate slab destruction */
log("destructed slab (used quota: ", alloc.consumed(), ")");
if (alloc.consumed() > 0) {
error("slab failed to release all backing store");
return;
}
{
log("test double-free detection - error message is expected");
Genode::Slab slab(SLAB_SIZE, BLOCK_SIZE, nullptr, &alloc);
void *p = nullptr;
{
Array_of_slab_elements array(slab, 4096, SLAB_SIZE, heap);
p = array.elem[1705];
}
slab.free(p, SLAB_SIZE);
{
Array_of_slab_elements array(slab, 4096, SLAB_SIZE, heap);
}
}
log("Test done");
}