set basic scripts to generate automatic shared object files using the benchmark ABI

This commit is contained in:
2024-11-18 15:43:42 +00:00
parent 794f593390
commit e88f566a59
11 changed files with 314 additions and 4 deletions

View File

@@ -115,7 +115,10 @@ void init_alloc(int num_chunks, int chunk_size)
* allocate fixed size chunk with bitmap allocator * allocate fixed size chunk with bitmap allocator
* this is our simplistic `malloc` function * 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; unsigned char updated_byte = 0;
int chunk_index = 0; int chunk_index = 0;

View File

@@ -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 <assert.h>
#include <cheriintrin.h>
#include <cheri/cheric.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#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;
}

View File

View File

@@ -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

View File

@@ -46,7 +46,7 @@ void init_alloc(int size_in_bytes)
* allocate len bytes with bump pointer allocator * allocate len bytes with bump pointer allocator
* this is our simplistic `malloc` function * this is our simplistic `malloc` function
*/ */
char *malloc(int len) void *malloc(size_t len)
{ {
char *chunk = buffer + count; char *chunk = buffer + count;
size_t rounded_len; /* for CHERI alignment */ size_t rounded_len; /* for CHERI alignment */

View File

@@ -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 <cheriintrin.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#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;
}

View File

@@ -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() ! */

View File

@@ -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

View File

@@ -19,10 +19,10 @@ The interface goes as the following:
- The linkage of the C program should consist either of a shared object file - 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 which is preferred. Or with a header file which can compile the appropriate
file at compile. 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. - [ ] 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. The extraction library to generate the decided performance counters is implemented.
ARM unclear documentation from the A profile manual gives a unclear picture of 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 exactly what the performance counters do. The script to extract it and to generate graphs