From e88f566a5922648309e128264d726cb549739f9a Mon Sep 17 00:00:00 2001 From: Akilan Date: Mon, 18 Nov 2024 15:43:42 +0000 Subject: [PATCH] set basic scripts to generate automatic shared object files using the benchmark ABI --- .../bitmap/{ => HugePage}/bitmap_alloc.c | 5 +- .../bitmap/{ => HugePage}/bitmap_alloc.h | 0 allocator/bitmap/Regular/bitmap_alloc.c | 207 ++++++++++++++++++ allocator/bitmap/Regular/bitmap_alloc.h | 0 allocator/bitmap/build.sh | 2 + .../bump_alloc/{ => HugePage}/bump_alloc.c | 2 +- .../bump_alloc/{ => HugePage}/bump_alloc.h | 0 allocator/bump_alloc/Regular/bump_alloc.c | 78 +++++++ allocator/bump_alloc/Regular/bump_alloc.h | 18 ++ allocator/bump_alloc/build.sh | 2 + allocator/readme.md | 4 +- 11 files changed, 314 insertions(+), 4 deletions(-) rename allocator/bitmap/{ => HugePage}/bitmap_alloc.c (98%) rename allocator/bitmap/{ => HugePage}/bitmap_alloc.h (100%) create mode 100644 allocator/bitmap/Regular/bitmap_alloc.c create mode 100644 allocator/bitmap/Regular/bitmap_alloc.h create mode 100644 allocator/bitmap/build.sh rename allocator/bump_alloc/{ => HugePage}/bump_alloc.c (98%) rename allocator/bump_alloc/{ => HugePage}/bump_alloc.h (100%) create mode 100644 allocator/bump_alloc/Regular/bump_alloc.c create mode 100644 allocator/bump_alloc/Regular/bump_alloc.h create mode 100644 allocator/bump_alloc/build.sh diff --git a/allocator/bitmap/bitmap_alloc.c b/allocator/bitmap/HugePage/bitmap_alloc.c similarity index 98% rename from allocator/bitmap/bitmap_alloc.c rename to allocator/bitmap/HugePage/bitmap_alloc.c index 737449a..53a8516 100644 --- a/allocator/bitmap/bitmap_alloc.c +++ b/allocator/bitmap/HugePage/bitmap_alloc.c @@ -115,7 +115,10 @@ void init_alloc(int num_chunks, int chunk_size) * allocate fixed size chunk with bitmap allocator * this is our simplistic `malloc` function */ -char *malloc() +// Length is not used but just kept +// to keep the integrity of the +// malloc shape. +void *malloc(size_t len) { unsigned char updated_byte = 0; int chunk_index = 0; diff --git a/allocator/bitmap/bitmap_alloc.h b/allocator/bitmap/HugePage/bitmap_alloc.h similarity index 100% rename from allocator/bitmap/bitmap_alloc.h rename to allocator/bitmap/HugePage/bitmap_alloc.h diff --git a/allocator/bitmap/Regular/bitmap_alloc.c b/allocator/bitmap/Regular/bitmap_alloc.c new file mode 100644 index 0000000..53a8516 --- /dev/null +++ b/allocator/bitmap/Regular/bitmap_alloc.c @@ -0,0 +1,207 @@ +/********************************** + * bitmap_alloc.c + * Jeremy.Singer@glasgow.ac.uk + * + * This is a simple fixed-size bitmap allocator. + * It mmaps a large buffer of + * NUM_CHUNKS * CHUNK_SIZE bytes + * then allocates this space in equally-sized + * chunks to client code. + * A side bitmap is required to keep track of which + * chunks are in use (corresponding bit set to 1) + * and which chunks are free (corresponding bit + * set to 0). There is one bit per allocatable chunk. + * + * This is _not_ a clever allocator, since it + * does a linear scan of the bitmap to find the + * first free chunk, which is expensive! + * More efficient scans could be easily incorporated. + * + * This is _not_ a general-purpose allocator, since + * it only allocates chunks of a fixed size. Further, + * this size is constrained to be small enough to allow + * exact bounds representation in CHERI capabilities. + * + * This is an initial simple memory allocator test + * for CHERI / Capable VMs. + * We explore capability alignment, + * representable bounds, narrowing operations + * and compiler intrinsic support. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "bitmap_alloc.h" + +#define BITS_PER_BYTE 8 + +char *buffer = NULL; /* allocation buffer */ +unsigned char *bitmap = NULL; /* bitmap for the buffer */ + +int buffer_size = 0; /* size of buffer (in bytes) */ +int bitmap_size = 0; /* size of bitmap (in bytes) */ +int bytes_per_chunk = 0; /* size of single chunk (in bytes) */ + +void init_alloc(int num_chunks, int chunk_size) +{ + int i = 0; + + /* we need to increase the num_chunks + * so every bit in bitmap will be used + */ + int adjusted_num_chunks = (num_chunks % BITS_PER_BYTE == 0) + ? num_chunks + : (num_chunks + (BITS_PER_BYTE - (num_chunks % BITS_PER_BYTE))); + + /* we need to increase the chunk_size + * so chunks will be CHERI aligned + * (i.e. 16 bytes for RISC-V 64-bit arch) + */ + int adjusted_chunk_size = + (chunk_size % (sizeof(void *)) == 0) + ? chunk_size + : (chunk_size + (sizeof(void *)) - (chunk_size % (sizeof(void *)))); + + /* check this chunk size is small enough so we can represent + * bounds precisely with CHERI compressed representation + */ + adjusted_chunk_size = cheri_representable_length(adjusted_chunk_size); + + /* request memory for our allocation buffer */ + char *res = mmap(NULL, adjusted_num_chunks * adjusted_chunk_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + /* request memory for our bitmap */ + bitmap = (unsigned char *) mmap(NULL, adjusted_num_chunks / BITS_PER_BYTE, + PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + + if (res == MAP_FAILED || bitmap == MAP_FAILED) + { + perror("error in initial mem allocation"); + exit(-1); + } + + /* NB mmap min bounds for capability is 1 page (4K) */ + buffer = res; + /* check buffer is aligned */ + assert((uintptr_t) buffer % sizeof(void *) == 0); + /* check bitmap is aligned */ + assert((uintptr_t) bitmap % sizeof(void *) == 0); + + bytes_per_chunk = adjusted_chunk_size; + buffer_size = adjusted_num_chunks * adjusted_chunk_size; + bitmap_size = adjusted_num_chunks / BITS_PER_BYTE; + + /* zero bitmap, since all chunks are free initially */ + for (i = 0; i < bitmap_size; i++) + { + bitmap[i] = 0; + } + + // set exact bounds for buffer and bitmap? + buffer = cheri_setbounds(buffer, buffer_size); + bitmap = cheri_setbounds(bitmap, bitmap_size); + return; +} + +/* + * allocate fixed size chunk with bitmap allocator + * this is our simplistic `malloc` function + */ +// Length is not used but just kept +// to keep the integrity of the +// malloc shape. +void *malloc(size_t len) +{ + unsigned char updated_byte = 0; + int chunk_index = 0; + char *chunk = NULL; + // iterate over all bits in bitmap, looking for a 0 + // when we find a 0, set it to 1 and + // return the corresponding chunk + // (setting its capability bounds) + int i = 0; + while (bitmap[i] == (unsigned char) 0xff) + { + i++; + if (i >= bitmap_size) + break; + } + // do we have a 0? + if (i < bitmap_size && bitmap[i] != (unsigned char) 0xff) + { + // find the lowest 0 ... + int j = 0; + // right shift until bottom bit is 0 + for (j = 0; j < BITS_PER_BYTE; j++) + { + int bit = (bitmap[i] >> j) & 1; + if (bit == 0) + { + break; + } + } + // now i is the word index, j is the bit index + // set this bit to 1 ... + // and work out the chunk to allocate + updated_byte = bitmap[i] + (unsigned char) (1 << j); + bitmap[i] = updated_byte; + + chunk_index = i * BITS_PER_BYTE + j; + chunk = buffer + (chunk_index * bytes_per_chunk); + + /* restrict capability range before returning ptr */ + chunk = cheri_setbounds(chunk, bytes_per_chunk); + } + + return chunk; +} + +void free(void *chunk) +{ + vaddr_t base = cheri_getbase(chunk); + vaddr_t buff_base = cheri_getbase(buffer); + /* calculate chunk index in buffer */ + int chunk_index = (base - buff_base) / bytes_per_chunk; + assert(chunk_index >= 0); + /* calculate corresponding bitmap index */ + int bitmap_index = chunk_index / BITS_PER_BYTE; + assert(bitmap_index < bitmap_size); + int bitmap_offset = chunk_index % BITS_PER_BYTE; + /* set this bitmap entry to 0 */ + unsigned char updated_byte = bitmap[bitmap_index] & (unsigned char) (~(1 << bitmap_offset)); + bitmap[bitmap_index] = updated_byte; + return; +} + +int num_used_chunks() +{ + int i = 0; + int used_chunks = 0; + + while (i < bitmap_size) + { + unsigned char x = bitmap[i]; + if (x != 0) + { + /* some used chunks here */ + unsigned char j; + for (j = 1; j <= x; j = j << 1) + { + if (x & j) + { + used_chunks++; + } + } + } + i++; + } + return used_chunks; +} \ No newline at end of file diff --git a/allocator/bitmap/Regular/bitmap_alloc.h b/allocator/bitmap/Regular/bitmap_alloc.h new file mode 100644 index 0000000..e69de29 diff --git a/allocator/bitmap/build.sh b/allocator/bitmap/build.sh new file mode 100644 index 0000000..cabf1a9 --- /dev/null +++ b/allocator/bitmap/build.sh @@ -0,0 +1,2 @@ +cc -g -Wall -shared -o malloc-huge.so -mabi=purecap-benchmark -lpthread HugePage/bitmap_alloc.c +cc -g -Wall -shared -o malloc-regular.so -mabi=purecap-benchmark -lpthread Regular/bitmap_alloc.c \ No newline at end of file diff --git a/allocator/bump_alloc/bump_alloc.c b/allocator/bump_alloc/HugePage/bump_alloc.c similarity index 98% rename from allocator/bump_alloc/bump_alloc.c rename to allocator/bump_alloc/HugePage/bump_alloc.c index b55bb27..5e011c5 100644 --- a/allocator/bump_alloc/bump_alloc.c +++ b/allocator/bump_alloc/HugePage/bump_alloc.c @@ -46,7 +46,7 @@ void init_alloc(int size_in_bytes) * allocate len bytes with bump pointer allocator * this is our simplistic `malloc` function */ -char *malloc(int len) +void *malloc(size_t len) { char *chunk = buffer + count; size_t rounded_len; /* for CHERI alignment */ diff --git a/allocator/bump_alloc/bump_alloc.h b/allocator/bump_alloc/HugePage/bump_alloc.h similarity index 100% rename from allocator/bump_alloc/bump_alloc.h rename to allocator/bump_alloc/HugePage/bump_alloc.h diff --git a/allocator/bump_alloc/Regular/bump_alloc.c b/allocator/bump_alloc/Regular/bump_alloc.c new file mode 100644 index 0000000..5e011c5 --- /dev/null +++ b/allocator/bump_alloc/Regular/bump_alloc.c @@ -0,0 +1,78 @@ +/********************************** + * bump_alloc.c + * Jeremy.Singer@glasgow.ac.uk + * + * This is a simple bump-pointer allocator. + * It mmaps a large buffer of SIZE bytes, + * then allocates this space in word-sized + * chunks to client code (in main fn). + * + * Initial simple memory allocator test. + * Explore capability narrowing operations + * and intrinsics for bound reporting. + */ + +#include +#include +#include +#include +#include + +#include "bump_alloc.h" + +int count = 0; /* number of bytes allocated so far*/ +int max = 0; /* upper limit for count */ +char *buffer = NULL; /* the allocation buffer */ + +void init_alloc(int size_in_bytes) +{ + /* request memory for our allocation buffer + * NB mmap min bounds for capability is 1 page (4K) + */ + char *res = mmap(NULL, size_in_bytes, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + + if (res == MAP_FAILED) + { + perror("error in initial mem allocation"); + exit(-1); + } + + buffer = res; + max = size_in_bytes; + return; +} + +/* + * allocate len bytes with bump pointer allocator + * this is our simplistic `malloc` function + */ +void *malloc(size_t len) +{ + char *chunk = buffer + count; + size_t rounded_len; /* for CHERI alignment */ + size_t new_count; /* for buffer overflow check */ + + /* ensure we can represent the capability accurately, + * see p30 of CHERI C/C++ Prog Guide (June 2020) + * www.cl.cam.ac.uk/techreports/UCAM-CL-TR-947 + */ + chunk = __builtin_align_up(chunk, ~cheri_representable_alignment_mask(len) + 1); + rounded_len = cheri_representable_length(len); + + new_count = (chunk + rounded_len) - buffer; + if (new_count > max) + { + /* out of bounds - don't allocate anything */ + chunk = 0; + } + else + { + /* restrict capability range before returning ptr */ + chunk = cheri_bounds_set_exact(chunk, rounded_len); + + /* update bytes allocated count */ + count = new_count; + } + + return chunk; +} \ No newline at end of file diff --git a/allocator/bump_alloc/Regular/bump_alloc.h b/allocator/bump_alloc/Regular/bump_alloc.h new file mode 100644 index 0000000..5dce22d --- /dev/null +++ b/allocator/bump_alloc/Regular/bump_alloc.h @@ -0,0 +1,18 @@ +/********************************** + * bump_alloc.h + * Jeremy.Singer@glasgow.ac.uk + * + * This is a simple bump-pointer allocator. + * It mmaps a large buffer of SIZE bytes, + * then allocates this space in word-sized + * chunks to client code (in main fn). + * + * Initial simple memory allocator test. + * Explore capability narrowing operations + * and intrinsics for bound reporting. + */ + +void init_alloc(int size_in_bytes); + +char *bump_alloc(int bytes); /* the simplest malloc */ + /* oh, and there's no free() ! */ \ No newline at end of file diff --git a/allocator/bump_alloc/build.sh b/allocator/bump_alloc/build.sh new file mode 100644 index 0000000..26c1db0 --- /dev/null +++ b/allocator/bump_alloc/build.sh @@ -0,0 +1,2 @@ +cc -g -Wall -shared -o malloc-huge.so -mabi=purecap-benchmark -lpthread HugePage/bump_alloc.c +cc -g -Wall -shared -o malloc-regular.so -mabi=purecap-benchmark -lpthread Regular/bump_alloc.c \ No newline at end of file diff --git a/allocator/readme.md b/allocator/readme.md index 3f03662..f05adf5 100644 --- a/allocator/readme.md +++ b/allocator/readme.md @@ -19,10 +19,10 @@ The interface goes as the following: - The linkage of the C program should consist either of a shared object file which is preferred. Or with a header file which can compile the appropriate file at compile. - - [ ] To write a script to compile and link shared object files. + - [x] To write a script to compile and link shared object files. - [ ] Automate generating header files. -## Automating the extracting of various performance counters. +## Automating the extracting of various performance counters and Parsing and analyzing the various benchmark metrics extracted. The extraction library to generate the decided performance counters is implemented. ARM unclear documentation from the A profile manual gives a unclear picture of exactly what the performance counters do. The script to extract it and to generate graphs