diff --git a/repos/base/run/slab.run b/repos/base/run/slab.run new file mode 100644 index 0000000000..98fce646d3 --- /dev/null +++ b/repos/base/run/slab.run @@ -0,0 +1,39 @@ +build "core init drivers/timer test/slab" + +create_boot_directory + +install_config { + + + + + + + + + + + + + + + + + + + + + + + + + +} + +build_boot_image "core init timer test-slab" + +append qemu_args "-nographic -m 128" + +run_genode_until {child "test-slab" exited with exit value 0.*\n} 100 + +puts "Test succeeded" diff --git a/repos/base/src/test/slab/main.cc b/repos/base/src/test/slab/main.cc new file mode 100644 index 0000000000..1f2ba92e9a --- /dev/null +++ b/repos/base/src/test/slab/main.cc @@ -0,0 +1,113 @@ +/* + * \brief Slab allocator test + * \author Norman Feske + * \date 2015-03-31 + * + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#include +#include +#include +#include +#include + + +using Genode::size_t; +using Genode::printf; + + +struct Array_of_slab_elements +{ + Genode::Slab &slab; + + 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 { }; + + /** + * Constructor + * + * \throw Alloc_failed + */ + Array_of_slab_elements(Genode::Slab &slab, size_t num_elem, size_t slab_size) + : + slab(slab), num_elem(num_elem), slab_size(slab_size) + { + elem = (void **)Genode::env()->heap()->alloc(_elem_array_size()); + + printf(" allocate %zu elements\n", num_elem); + for (size_t i = 0; i < num_elem; i++) + if (!slab.alloc(slab_size, &elem[i])) + throw Alloc_failed(); + } + + ~Array_of_slab_elements() + { + printf(" free %zu elements\n", num_elem); + for (size_t i = 0; i < num_elem; i++) + slab.free(elem[i], slab_size); + + Genode::env()->heap()->free(elem, _elem_array_size()); + } +}; + + +int main(int argc, char **argv) +{ + printf("--- slab test ---\n"); + + static Timer::Connection timer; + + enum { SLAB_SIZE = 16, BLOCK_SIZE = 256 }; + static Genode::Allocator_guard alloc(Genode::env()->heap(), ~0UL); + + { + Genode::Slab slab(SLAB_SIZE, BLOCK_SIZE, nullptr, &alloc); + + for (unsigned i = 1; i <= 10; i++) { + printf("round %u (used quota: %zu, time: %ld ms)\n", + i, alloc.consumed(), timer.elapsed_ms()); + + Array_of_slab_elements array(slab, i*100000, SLAB_SIZE); + printf(" allocation completed (used quota: %zu", alloc.consumed()); + } + + printf(" finished (used quota: %zu, time: %ld ms)\n", + alloc.consumed(), timer.elapsed_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 = 36 }; + if (alloc.consumed() > 2*(BLOCK_SIZE + HEAP_OVERHEAD)) { + PERR("slab failed to release empty slab blocks"); + return -1; + } + } + + /* validate slab destruction */ + printf("destructed slab (used quota: %zu)\n", alloc.consumed()); + if (alloc.consumed() > 0) { + PERR("slab failed to release all backing store"); + return -2; + } + + return 0; +} diff --git a/repos/base/src/test/slab/target.mk b/repos/base/src/test/slab/target.mk new file mode 100644 index 0000000000..ca9d80fd3d --- /dev/null +++ b/repos/base/src/test/slab/target.mk @@ -0,0 +1,3 @@ +TARGET = test-slab +SRC_CC = main.cc +LIBS = base