added huge pages tests
This commit is contained in:
@@ -166,7 +166,7 @@ void *malloc(size_t sz) {
|
||||
// if (heap + sz > heap_start + HEAP_SIZE) return NULL;
|
||||
// heap += sz;
|
||||
// return heap - sz;
|
||||
malloc_called += 1;
|
||||
malloc_called += 2;
|
||||
return MALLOCCHERI(sz);
|
||||
}
|
||||
|
||||
|
||||
220
allocator/testallocator/allocBitmap.c
Normal file
220
allocator/testallocator/allocBitmap.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/**********************************
|
||||
* 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"
|
||||
#include "custom_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);
|
||||
char *res = (char *)MALLOCCHERI(adjusted_num_chunks * adjusted_chunk_size);
|
||||
|
||||
char *bitmap = (char *)MALLOCCHERI(adjusted_num_chunks / BITS_PER_BYTE);
|
||||
/* 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.
|
||||
|
||||
int notrun = 0;
|
||||
|
||||
void *malloc(size_t len)
|
||||
{
|
||||
|
||||
if (notrun == 0){
|
||||
init_alloc(500,1000);
|
||||
notrun = 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
10
allocator/testallocator/benchmarks/kmeans/CMakeLists.txt
Normal file
10
allocator/testallocator/benchmarks/kmeans/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
add_executable(kmeans kmeans-pthread.c)
|
||||
target_link_libraries(kmeans PRIVATE pthread)
|
||||
|
||||
add_coz_run_target(run_kmeans_small COMMAND $<TARGET_FILE:kmeans> -d 3 -c 100 -p 10000 -s 100)
|
||||
add_coz_run_target(run_kmeans_large COMMAND $<TARGET_FILE:kmeans> -d 3 -c 100 -p 100000 -s 1000)
|
||||
|
||||
add_test(
|
||||
NAME test_run_kmeans
|
||||
COMMAND ${PROJECT_SOURCE_DIR}/benchmarks/check-output.sh ${PROJECT_SOURCE_DIR}/coz run --- $<TARGET_FILE:kmeans>
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
|
||||
395
allocator/testallocator/benchmarks/kmeans/bitmap.h
Normal file
395
allocator/testallocator/benchmarks/kmeans/bitmap.h
Normal file
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Bharath Ramesh <bramesh.dev@gmail.com>
|
||||
*
|
||||
* Distributed under the terms of GNU LGPL, version 2.1
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
// #include "brmalloc.h"
|
||||
|
||||
// ------------
|
||||
// User defined
|
||||
#define MIN_ALLOC_SIZE ((size_t)8U)
|
||||
#define MAX_ALLOC_SIZE ((size_t)4096U)
|
||||
#define MAX_NUM_ALLOCS 8192
|
||||
#define NUM_ITERATIONS 32UNIMPLEMENTED
|
||||
|
||||
// ------------
|
||||
|
||||
#define BITS_PER_LONG 64
|
||||
#define LOG_BITS_PER_BYTE 3
|
||||
#define LOG_BITS_PER_LONG 6
|
||||
#define LOG_BYTES_PER_LONG 3
|
||||
#define MAX_LONG 0xffffffffffffffff
|
||||
#define K ((size_t)1024U)
|
||||
#define M ((size_t)1024U * K)
|
||||
#define G ((size_t)1024U * M)
|
||||
#define MALLOC_OVERHEAD ((size_t)16U)
|
||||
|
||||
#ifndef ABORT
|
||||
#define ABORT() abort()
|
||||
#endif
|
||||
|
||||
#ifndef EXIT_ERR
|
||||
#define EXIT_ERR() exit(EXIT_FAILURE)
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG
|
||||
#include <stdio.h>
|
||||
#define DEBUG(fmt, args...) printf("%d, %s: " fmt, __LINE__, __FUNCTION__, ##args)
|
||||
#endif
|
||||
|
||||
#ifndef MALLOC_QUANTA
|
||||
#define MALLOC_QUANTA ((size_t)16U)
|
||||
#endif
|
||||
|
||||
#ifndef MALLOC_THRESHOLD
|
||||
#define MALLOC_THRESHOLD ((size_t)1U * M)
|
||||
#endif
|
||||
|
||||
#ifndef MALLOC_ZONE_SIZE
|
||||
#define MALLOC_ZONE_SIZE ((size_t)16U * M)
|
||||
#endif
|
||||
|
||||
#ifndef MMAP
|
||||
#include <sys/mman.h>
|
||||
#define MMAP_FLAGS (MAP_ANONYMOUS | MAP_PRIVATE)
|
||||
#define MMAP_PROT (PROT_READ | PROT_WRITE)
|
||||
#define MMAP(s) mmap (0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)
|
||||
#define MUNMAP(a, s) munmap ((a), (s))
|
||||
#endif
|
||||
|
||||
struct __malloc_zone_type {
|
||||
unsigned char *bmap;
|
||||
size_t bmap_longs;
|
||||
size_t free_size;
|
||||
uint64_t id;
|
||||
void *region;
|
||||
uint64_t start_byte;
|
||||
struct __malloc_zone_type *next;
|
||||
};
|
||||
|
||||
typedef struct __malloc_zone_type malloc_zone_t;
|
||||
|
||||
static malloc_zone_t *mz_head = NULL, *mz_tail = NULL;
|
||||
static uint8_t mqbits = 0;
|
||||
|
||||
static inline void
|
||||
free_region (malloc_zone_t *mz, uint64_t loc, size_t nbytes)
|
||||
{
|
||||
unsigned char *bmap;
|
||||
size_t bmap_longs;
|
||||
uint64_t i, i_b, j_b, lbits, nbits, pattern, *wordptr;
|
||||
|
||||
lbits = nbits = nbytes >> mqbits;
|
||||
i_b = loc >> LOG_BITS_PER_LONG;
|
||||
j_b = loc - (i_b << LOG_BITS_PER_LONG);
|
||||
bmap = mz->bmap;
|
||||
bmap_longs = mz->bmap_longs;
|
||||
for (i = i_b; i < bmap_longs; ++i) {
|
||||
if (lbits == 0)
|
||||
break;
|
||||
|
||||
wordptr = (uint64_t *) bmap + i;
|
||||
if (i == i_b) {
|
||||
if ((j_b + nbits) < BITS_PER_LONG) {
|
||||
pattern = ((uint64_t) 1 << nbits) - 1;
|
||||
pattern = ~(pattern << j_b);
|
||||
*wordptr &= pattern;
|
||||
return;
|
||||
}
|
||||
|
||||
pattern = ~(MAX_LONG << j_b);
|
||||
*wordptr &= pattern;
|
||||
lbits -= (BITS_PER_LONG -j_b);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lbits >= BITS_PER_LONG) {
|
||||
*wordptr = 0;
|
||||
lbits -= BITS_PER_LONG;
|
||||
continue;
|
||||
}
|
||||
|
||||
pattern = ~(((uint64_t) 1 << lbits) - 1);
|
||||
*wordptr &= pattern;
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
get_region (malloc_zone_t *mz, size_t nbytes)
|
||||
{
|
||||
unsigned char *bmap;
|
||||
size_t bmap_longs;
|
||||
uint64_t i = 0, i_b, j, j_b, l, nbits, rbits, pattern, word, *wordptr;
|
||||
int64_t loc = -1;
|
||||
|
||||
nbits = rbits = nbytes >> mqbits;
|
||||
bmap = mz->bmap;
|
||||
bmap_longs = mz->bmap_longs;
|
||||
l = mz->start_byte;
|
||||
while (i < bmap_longs) {
|
||||
if (rbits == 0)
|
||||
break;
|
||||
|
||||
word = *((uint64_t *) bmap + l);
|
||||
if (word == MAX_LONG) {
|
||||
loc = -1;
|
||||
rbits = nbits;
|
||||
++i;
|
||||
++l;
|
||||
if (l == bmap_longs)
|
||||
l = 0;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (word == 0) {
|
||||
if (rbits >= BITS_PER_LONG) {
|
||||
rbits -= BITS_PER_LONG;
|
||||
if (loc == -1)
|
||||
loc = l << LOG_BITS_PER_LONG;
|
||||
|
||||
++i;
|
||||
++l;
|
||||
if (l == bmap_longs) {
|
||||
l = 0;
|
||||
loc = -1;
|
||||
rbits = nbits;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
rbits = 0;
|
||||
if (loc == -1)
|
||||
loc = l << LOG_BITS_PER_LONG;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (rbits >= BITS_PER_LONG) {
|
||||
loc = -1;
|
||||
rbits = nbits;
|
||||
++i;
|
||||
++l;
|
||||
if (l == bmap_longs)
|
||||
l = 0;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = 0; j < BITS_PER_LONG; ++j) {
|
||||
if (rbits == 0)
|
||||
break;
|
||||
|
||||
if ((word >> j) & 1) {
|
||||
loc = -1;
|
||||
rbits = nbits;
|
||||
++i;
|
||||
++l;
|
||||
if (l == bmap_longs)
|
||||
l = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
--rbits;
|
||||
if (loc == -1)
|
||||
loc = (l << LOG_BITS_PER_LONG) + j;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rbits != 0) || (loc == -1))
|
||||
return -1;
|
||||
|
||||
mz->start_byte = (loc + nbits) >> LOG_BITS_PER_LONG;
|
||||
i_b = loc >> LOG_BITS_PER_LONG;
|
||||
j_b = loc - (i_b << LOG_BITS_PER_LONG);
|
||||
rbits = nbits;
|
||||
for (i = i_b; i < bmap_longs; ++i) {
|
||||
if (rbits == 0)
|
||||
break;
|
||||
|
||||
wordptr = (uint64_t *) bmap + i;
|
||||
if (i == i_b) {
|
||||
if ((j_b + nbits) < BITS_PER_LONG) {
|
||||
pattern = ((uint64_t) 1 << nbits) - 1;
|
||||
pattern = pattern << j_b;
|
||||
*wordptr |= pattern;
|
||||
return loc;
|
||||
}
|
||||
|
||||
pattern = MAX_LONG << j_b;
|
||||
*wordptr |= pattern;
|
||||
rbits -= (BITS_PER_LONG - j_b);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rbits >= BITS_PER_LONG) {
|
||||
*wordptr = MAX_LONG;
|
||||
rbits -= BITS_PER_LONG;
|
||||
continue;
|
||||
}
|
||||
|
||||
pattern = ((uint64_t) 1 << rbits) - 1;
|
||||
*wordptr |= pattern;
|
||||
return loc;
|
||||
}
|
||||
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
static inline malloc_zone_t *
|
||||
new_malloc_zone (void)
|
||||
{
|
||||
size_t bmap_size, bmap_longs;
|
||||
malloc_zone_t *mz;
|
||||
void *region;
|
||||
|
||||
region = MMAP (MALLOC_ZONE_SIZE);
|
||||
if (region == MAP_FAILED) {
|
||||
DEBUG ("ERROR: MMAP failed.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bmap_size = (MALLOC_ZONE_SIZE / MALLOC_QUANTA) >> LOG_BITS_PER_BYTE;
|
||||
bmap_longs = bmap_size >> LOG_BYTES_PER_LONG;
|
||||
mz = (malloc_zone_t *) malloc (sizeof (malloc_zone_t));
|
||||
mz->bmap = (unsigned char *) malloc (bmap_size);
|
||||
if (mz->bmap == NULL) {
|
||||
DEBUG ("ERROR: Unable to allocate bitmap.\n");
|
||||
free (mz);
|
||||
MUNMAP (region, MALLOC_ZONE_SIZE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset (mz->bmap, 0, bmap_size);
|
||||
mz->bmap_longs = bmap_longs;
|
||||
mz->free_size = MALLOC_ZONE_SIZE;
|
||||
mz->id = (uint64_t) mz;
|
||||
mz->region = region;
|
||||
mz->start_byte = 0;
|
||||
mz->next = NULL;
|
||||
if (mz_tail != NULL)
|
||||
mz_tail->next = mz;
|
||||
|
||||
mz_tail = mz;
|
||||
if (mz_head == NULL)
|
||||
mz_head = mz;
|
||||
|
||||
return mz;
|
||||
}
|
||||
|
||||
static void __attribute__ ((constructor))
|
||||
brm_init (void)
|
||||
{
|
||||
uint8_t i, no_ones;
|
||||
size_t size;
|
||||
|
||||
no_ones = 0;
|
||||
size = MALLOC_QUANTA;
|
||||
for (i = 0; i < BITS_PER_LONG; ++i) {
|
||||
if ((size >> i) & 1) {
|
||||
++no_ones;
|
||||
if (no_ones > 1) {
|
||||
DEBUG ("ERROR: MALLOC_QUANTA not power of "
|
||||
"2.\n");
|
||||
EXIT_ERR ();
|
||||
}
|
||||
|
||||
mqbits = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (no_ones == 0) {
|
||||
DEBUG ("ERROR: MALLOC_QUANTA set to 0 (zero).\n");
|
||||
EXIT_ERR ();
|
||||
}
|
||||
|
||||
if (new_malloc_zone () == NULL) {
|
||||
DEBUG ("ERROR: new_malloc_zone failed.\n");
|
||||
EXIT_ERR ();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
brm_free (void *ptr)
|
||||
{
|
||||
uint64_t *base;
|
||||
malloc_zone_t *mz;
|
||||
int64_t offset;
|
||||
size_t size;
|
||||
|
||||
base = (uint64_t *) ptr - 2;
|
||||
mz = (malloc_zone_t *) *((uint64_t *) base);
|
||||
size = (size_t) *((uint64_t *) base + 1);
|
||||
if (mz->id != (uint64_t) mz) {
|
||||
DEBUG ("ptr: %p, base: %p\n", ptr, base);
|
||||
DEBUG ("ERROR: data corruption.\n");
|
||||
ABORT ();
|
||||
}
|
||||
|
||||
offset = ((void *) base - mz->region) >> mqbits;
|
||||
free_region (mz, offset, size);
|
||||
mz->free_size += size;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void *
|
||||
brm_malloc (size_t size)
|
||||
{
|
||||
uint64_t addr;
|
||||
malloc_zone_t *mz;
|
||||
size_t nbytes;
|
||||
int64_t offset;
|
||||
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
nbytes = (size + MALLOC_OVERHEAD + MALLOC_QUANTA - 1) &
|
||||
~(MALLOC_QUANTA - 1);
|
||||
// printf(nbytes);
|
||||
// if (nbytes >= MALLOC_THRESHOLD) {
|
||||
// DEBUG ("UNIMPLEMENTED\n");
|
||||
// EXIT_ERR();
|
||||
// }
|
||||
|
||||
mz = mz_head;
|
||||
while (1) {
|
||||
if (nbytes > mz->free_size) {
|
||||
DEBUG ("UNIMPLEMENTED\n");
|
||||
EXIT_ERR ();
|
||||
}
|
||||
|
||||
offset = get_region (mz, nbytes);
|
||||
if (offset == -1) {
|
||||
mz = mz->next;
|
||||
if (mz == NULL) {
|
||||
if ((mz = new_malloc_zone ()) == NULL) {
|
||||
DEBUG ("ERROR: new_malloc zone "
|
||||
"failed.\n");
|
||||
EXIT_ERR ();
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
mz->free_size -= nbytes;
|
||||
addr = (uint64_t) mz->region + ((size_t) offset << mqbits);
|
||||
*((uint64_t *) addr) = (uint64_t) mz;
|
||||
*((uint64_t *) addr + 1) = (uint64_t) nbytes;
|
||||
break;
|
||||
}
|
||||
|
||||
return (void *) (addr + 2 * sizeof (uint64_t));
|
||||
}
|
||||
3
allocator/testallocator/benchmarks/kmeans/build.sh
Normal file
3
allocator/testallocator/benchmarks/kmeans/build.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
# git pull origin main
|
||||
cc -g -O2 -Wall -o kmeans-pthread.out -lpthread kmeans-pthread.c
|
||||
# sudo time pmcstat -d -w 1 -p l1d_tlb_rd -p l2d_tlb_rd -p l1d_tlb_refill -p cpu_cycles -p dtlb_walk -p stall_backend ./kmeans-pthread.out
|
||||
93
allocator/testallocator/benchmarks/kmeans/coz.h
Normal file
93
allocator/testallocator/benchmarks/kmeans/coz.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Charlie Curtsinger and Emery Berger,
|
||||
* University of Massachusetts Amherst
|
||||
* This file is part of the Coz project. See LICENSE.md file at the top-level
|
||||
* directory of this distribution and at http://github.com/plasma-umass/coz.
|
||||
*/
|
||||
|
||||
#if !defined(COZ_H)
|
||||
#define COZ_H
|
||||
|
||||
#ifndef __USE_GNU
|
||||
# define __USE_GNU
|
||||
#endif
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h> /* for memcpy hack below */
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define COZ_COUNTER_TYPE_THROUGHPUT 1
|
||||
#define COZ_COUNTER_TYPE_BEGIN 2
|
||||
#define COZ_COUNTER_TYPE_END 3
|
||||
|
||||
// Declare dlsym as a weak reference so libdl isn't required
|
||||
void* dlsym(void* handle, const char* symbol) __attribute__((weak));
|
||||
|
||||
// Counter info struct, containing both a counter and backoff size
|
||||
typedef struct {
|
||||
size_t count; // The actual count
|
||||
size_t backoff; // Used to batch updates to the shared counter. Currently unused.
|
||||
} coz_counter_t;
|
||||
|
||||
// The type of the _coz_get_counter function
|
||||
typedef coz_counter_t* (*coz_get_counter_t)(int, const char*);
|
||||
|
||||
// Locate and invoke _coz_get_counter
|
||||
static coz_counter_t* _call_coz_get_counter(int type, const char* name) {
|
||||
static unsigned char _initialized = 0;
|
||||
static coz_get_counter_t fn; // The pointer to _coz_get_counter
|
||||
|
||||
if(!_initialized) {
|
||||
if(dlsym) {
|
||||
// Locate the _coz_get_counter method
|
||||
void* p = dlsym(RTLD_DEFAULT, "_coz_get_counter");
|
||||
|
||||
// Use memcpy to avoid pedantic GCC complaint about storing function pointer in void*
|
||||
memcpy(&fn, &p, sizeof(p));
|
||||
}
|
||||
|
||||
_initialized = 1;
|
||||
}
|
||||
|
||||
// Call the function, or return null if profiler is not found
|
||||
if(fn) return fn(type, name);
|
||||
else return 0;
|
||||
}
|
||||
|
||||
// Macro to initialize and increment a counter
|
||||
#define COZ_INCREMENT_COUNTER(type, name) \
|
||||
if(1) { \
|
||||
static unsigned char _initialized = 0; \
|
||||
static coz_counter_t* _counter = 0; \
|
||||
\
|
||||
if(!_initialized) { \
|
||||
_counter = _call_coz_get_counter(type, name); \
|
||||
_initialized = 1; \
|
||||
} \
|
||||
if(_counter) { \
|
||||
__atomic_add_fetch(&_counter->count, 1, __ATOMIC_RELAXED); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define STR2(x) #x
|
||||
#define STR(x) STR2(x)
|
||||
|
||||
#define COZ_PROGRESS_NAMED(name) COZ_INCREMENT_COUNTER(COZ_COUNTER_TYPE_THROUGHPUT, name)
|
||||
|
||||
#define COZ_PROGRESS COZ_INCREMENT_COUNTER(COZ_COUNTER_TYPE_THROUGHPUT, __FILE__ ":" STR(__LINE__))
|
||||
#define COZ_BEGIN(name) COZ_INCREMENT_COUNTER(COZ_COUNTER_TYPE_BEGIN, name)
|
||||
#define COZ_END(name) COZ_INCREMENT_COUNTER(COZ_COUNTER_TYPE_END, name)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
7
allocator/testallocator/benchmarks/kmeans/debug.txt
Normal file
7
allocator/testallocator/benchmarks/kmeans/debug.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Regular mmap:
|
||||
723.17 real
|
||||
modified mmap:
|
||||
723.17 real
|
||||
|
||||
modified mmap:
|
||||
156.65 real
|
||||
407
allocator/testallocator/benchmarks/kmeans/kmeans-pthread.c
Normal file
407
allocator/testallocator/benchmarks/kmeans/kmeans-pthread.c
Normal file
@@ -0,0 +1,407 @@
|
||||
/* Copyright (c) 2007-2009, Stanford University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Stanford University nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "stddefines.h"
|
||||
|
||||
#include "coz.h"
|
||||
|
||||
// #define malloc my_malloc
|
||||
// #define free my_free
|
||||
|
||||
#define DEF_NUM_POINTS 150000
|
||||
#define DEF_NUM_MEANS 100
|
||||
#define DEF_DIM 40
|
||||
#define DEF_GRID_SIZE 100
|
||||
|
||||
// #define DEF_NUM_POINTS 100000
|
||||
// #define DEF_NUM_MEANS 100
|
||||
// #define DEF_DIM 40
|
||||
// #define DEF_GRID_SIZE 1000
|
||||
|
||||
// #define DEF_NUM_POINTS 1000
|
||||
// #define DEF_NUM_MEANS 10
|
||||
// #define DEF_DIM 3
|
||||
// #define DEF_GRID_SIZE 100
|
||||
|
||||
#define false 0
|
||||
#define true 1
|
||||
|
||||
int num_points; // number of vectors
|
||||
int dim; // Dimension of each vector
|
||||
int num_means; // number of clusters
|
||||
int grid_size; // size of each dimension of vector space
|
||||
int modified;
|
||||
int num_pts = 0;
|
||||
|
||||
int **points;
|
||||
int **means;
|
||||
int *clusters;
|
||||
|
||||
typedef struct {
|
||||
int start_idx;
|
||||
int num_pts;
|
||||
int *sum;
|
||||
} thread_arg;
|
||||
|
||||
/** dump_points()
|
||||
* Helper function to print out the points
|
||||
*/
|
||||
void dump_points(int **vals, int rows)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < rows; i++)
|
||||
{
|
||||
for (j = 0; j < dim; j++)
|
||||
{
|
||||
dprintf("%5d ",vals[i][j]);
|
||||
}
|
||||
// dprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** parse_args()
|
||||
* Parse the user arguments
|
||||
*/
|
||||
void parse_args(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
num_points = DEF_NUM_POINTS;
|
||||
num_means = DEF_NUM_MEANS;
|
||||
dim = DEF_DIM;
|
||||
grid_size = DEF_GRID_SIZE;
|
||||
|
||||
while ((c = getopt(argc, argv, "d:c:p:s:")) != EOF)
|
||||
{
|
||||
switch (c) {
|
||||
case 'd':
|
||||
dim = atoi(optarg);
|
||||
break;
|
||||
case 'c':
|
||||
num_means = atoi(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
num_points = atoi(optarg);
|
||||
break;
|
||||
case 's':
|
||||
grid_size = atoi(optarg);
|
||||
break;
|
||||
case '?':
|
||||
printf("Usage: %s -d <vector dimension> -c <num clusters> -p <num points> -s <grid size>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (dim <= 0 || num_means <= 0 || num_points <= 0 || grid_size <= 0) {
|
||||
printf("Illegal argument value. All values must be numeric and greater than 0\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Dimension = %d\n", dim);
|
||||
printf("Number of clusters = %d\n", num_means);
|
||||
printf("Number of points = %d\n", num_points);
|
||||
printf("Size of each dimension = %d\n", grid_size);
|
||||
}
|
||||
|
||||
/** generate_points()
|
||||
* Generate the points
|
||||
*/
|
||||
void generate_points(int **pts, int size)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i=0; i<size; i++)
|
||||
{
|
||||
for (j=0; j<dim; j++)
|
||||
{
|
||||
pts[i][j] = rand() % grid_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** get_sq_dist()
|
||||
* Get the squared distance between 2 points
|
||||
*/
|
||||
static inline unsigned int get_sq_dist(int *v1, int *v2)
|
||||
{
|
||||
int i;
|
||||
|
||||
unsigned int sum = 0;
|
||||
for (i = 0; i < dim; i++)
|
||||
{
|
||||
sum += ((v1[i] - v2[i]) * (v1[i] - v2[i]));
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/** add_to_sum()
|
||||
* Helper function to update the total distance sum
|
||||
*/
|
||||
void add_to_sum(int *sum, int *point)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dim; i++)
|
||||
{
|
||||
sum[i] += point[i];
|
||||
}
|
||||
}
|
||||
|
||||
/** find_clusters()
|
||||
* Find the cluster that is most suitable for a given set of points
|
||||
*/
|
||||
void *find_clusters(void *arg)
|
||||
{
|
||||
thread_arg *t_arg = (thread_arg *)arg;
|
||||
int i, j;
|
||||
unsigned int min_dist, cur_dist;
|
||||
int min_idx;
|
||||
int start_idx = t_arg->start_idx;
|
||||
int end_idx = start_idx + t_arg->num_pts;
|
||||
|
||||
for (i = start_idx; i < end_idx; i++)
|
||||
{
|
||||
min_dist = get_sq_dist(points[i], means[0]);
|
||||
min_idx = 0;
|
||||
for (j = 1; j < num_means; j++)
|
||||
{
|
||||
cur_dist = get_sq_dist(points[i], means[j]);
|
||||
if (cur_dist < min_dist)
|
||||
{
|
||||
min_dist = cur_dist;
|
||||
min_idx = j;
|
||||
}
|
||||
}
|
||||
|
||||
if (clusters[i] != min_idx)
|
||||
{
|
||||
clusters[i] = min_idx;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
COZ_PROGRESS_NAMED("clusters found");
|
||||
}
|
||||
|
||||
return (void *)0;
|
||||
}
|
||||
|
||||
/** calc_means()
|
||||
* Compute the means for the various clusters
|
||||
*/
|
||||
void *calc_means(void *arg)
|
||||
{
|
||||
int i, j, grp_size;
|
||||
int *sum;
|
||||
thread_arg *t_arg = (thread_arg *)arg;
|
||||
int start_idx = t_arg->start_idx;
|
||||
int end_idx = start_idx + t_arg->num_pts;
|
||||
|
||||
sum = t_arg->sum;
|
||||
|
||||
for (i = start_idx; i < end_idx; i++)
|
||||
{
|
||||
memset(sum, 0, dim * sizeof(int));
|
||||
grp_size = 0;
|
||||
|
||||
for (j = 0; j < num_points; j++)
|
||||
{
|
||||
if (clusters[j] == i)
|
||||
{
|
||||
add_to_sum(sum, points[j]);
|
||||
grp_size++;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < dim; j++)
|
||||
{
|
||||
//dprintf("div sum = %d, grp size = %d\n", sum[j], grp_size);
|
||||
if (grp_size != 0)
|
||||
{
|
||||
means[i][j] = sum[j] / grp_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
// free(sum);
|
||||
return (void *)0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
// sleep(10);
|
||||
|
||||
// Extra code snippet added
|
||||
// printf("Initial alloc called\n");
|
||||
//INITAlloc();
|
||||
// INITREGULARALLOC();
|
||||
// init_malloc();
|
||||
|
||||
int num_procs, curr_point;
|
||||
int i;
|
||||
pthread_t *pid;
|
||||
pthread_attr_t attr;
|
||||
thread_arg *arg;
|
||||
int num_per_thread, excess;
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
points = (int **)malloc(sizeof(int *) * num_points);
|
||||
for (i=0; i<num_points; i++)
|
||||
{
|
||||
points[i] = (int *)malloc(sizeof(int) * dim);
|
||||
}
|
||||
printf("Generating points\n");
|
||||
generate_points(points, num_points);
|
||||
|
||||
|
||||
// printf("calling malloc after generate\n");
|
||||
means = (int **)malloc(sizeof(int *) * num_means);
|
||||
for (i=0; i<num_means; i++)
|
||||
{
|
||||
means[i] = (int *)malloc(sizeof(int) * dim);
|
||||
}
|
||||
// dprintf("Generating means\n");
|
||||
generate_points(means, num_means);
|
||||
|
||||
clusters = (int *)malloc(sizeof(int) * num_points);
|
||||
memset(clusters, -1, sizeof(int) * num_points);
|
||||
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
|
||||
CHECK_ERROR((num_procs = sysconf(_SC_NPROCESSORS_ONLN)) <= 0);
|
||||
|
||||
CHECK_ERROR( (pid = (pthread_t *)malloc(sizeof(pthread_t) * num_procs)) == NULL);
|
||||
|
||||
modified = true;
|
||||
|
||||
printf("Starting iterative algorithm\n");
|
||||
|
||||
/* Create the threads to process the distances between the various
|
||||
points and repeat until modified is no longer valid */
|
||||
int num_threads;
|
||||
while (modified)
|
||||
{
|
||||
// printf("Inside loop\n");
|
||||
num_per_thread = num_points / num_procs;
|
||||
excess = num_points % num_procs;
|
||||
modified = false;
|
||||
// printf("Modified set to false\n");
|
||||
// printf(".");
|
||||
// printf("Point printed\n");
|
||||
curr_point = 0;
|
||||
num_threads = 0;
|
||||
|
||||
while (curr_point < num_points) {
|
||||
// printf("Inside secondary while loop\n");
|
||||
CHECK_ERROR((arg = (thread_arg *)malloc(sizeof(thread_arg))) == NULL);
|
||||
arg->start_idx = curr_point;
|
||||
arg->num_pts = num_per_thread;
|
||||
if (excess > 0) {
|
||||
arg->num_pts++;
|
||||
excess--;
|
||||
}
|
||||
CHECK_ERROR((pthread_create(&(pid[num_threads++]), &attr, find_clusters,
|
||||
(void *)(arg))) != 0);
|
||||
curr_point += arg->num_pts;
|
||||
}
|
||||
// printf("left while loop\n");
|
||||
|
||||
assert (num_threads == num_procs);
|
||||
for (i = 0; i < num_threads; i++) {
|
||||
pthread_join(pid[i], NULL);
|
||||
}
|
||||
|
||||
num_per_thread = num_means / num_procs;
|
||||
excess = num_means % num_procs;
|
||||
curr_point = 0;
|
||||
num_threads = 0;
|
||||
|
||||
// printf("reaches here \n");
|
||||
while (curr_point < num_means) {
|
||||
// printf("enters while loop \n");
|
||||
CHECK_ERROR((arg = (thread_arg *)malloc(sizeof(thread_arg))) == NULL);
|
||||
// printf("succesfully runs \n");
|
||||
arg->start_idx = curr_point;
|
||||
// printf("Running malloc \n");
|
||||
arg->sum = (int *)malloc(dim * sizeof(int));
|
||||
// printf("Finished malloc \n");
|
||||
arg->num_pts = num_per_thread;
|
||||
if (excess > 0) {
|
||||
arg->num_pts++;
|
||||
excess--;
|
||||
}
|
||||
|
||||
// printf("Running create \n");
|
||||
CHECK_ERROR((pthread_create(&(pid[num_threads++]), &attr, calc_means,
|
||||
(void *)(arg))) != 0);
|
||||
// printf("Create complete \n");
|
||||
curr_point += arg->num_pts;
|
||||
}
|
||||
|
||||
// printf("Running secondary join \n");
|
||||
|
||||
assert (num_threads == num_procs);
|
||||
for (i = 0; i < num_threads; i++) {
|
||||
pthread_join(pid[i], NULL);
|
||||
}
|
||||
// printf("Left while loop \n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
// dprintf("\n\nFinal means:\n");
|
||||
dump_points(means, num_means);
|
||||
|
||||
// for (i = 0; i < num_points; i++)
|
||||
// free(points[i]);
|
||||
// free(points);
|
||||
|
||||
// for (i = 0; i < num_means; i++)
|
||||
// {
|
||||
// free(means[i]);
|
||||
// }
|
||||
// free(means);
|
||||
// free(clusters);
|
||||
|
||||
// CLEARALLOC();
|
||||
|
||||
return 0;
|
||||
}
|
||||
46
allocator/testallocator/benchmarks/kmeans/pseduocode.c
Normal file
46
allocator/testallocator/benchmarks/kmeans/pseduocode.c
Normal file
@@ -0,0 +1,46 @@
|
||||
// Quick malloc implementation with mmap
|
||||
// void* malloc(size_t sz)
|
||||
// {
|
||||
// sz = __builtin_align_up(sz, _Alignof(max_align_t));
|
||||
// MallocCounter -= sz;
|
||||
// void *ptrLink = &ptr[MallocCounter];
|
||||
// ptrLink = cheri_setbounds(ptrLink, sz);
|
||||
|
||||
// return ptrLink;
|
||||
// }
|
||||
|
||||
// // Quick cheri free implementation
|
||||
// void free(void *ptr) {
|
||||
// int len = cheri_getlen(ptr);
|
||||
// munmap(ptr, len);
|
||||
// }
|
||||
|
||||
// Init_alloc(void) {
|
||||
// size_t sz;
|
||||
// // Pre Allocate 400 MB
|
||||
// sz = 1073741824;
|
||||
|
||||
// fd = shm_create_largepage(SHM_ANON, O_CREAT | O_RDWR, 1, SHM_LARGEPAGE_ALLOC_DEFAULT, 0);
|
||||
|
||||
// ptr = mmap(NULL, sz,
|
||||
// PROT_READ|PROT_WRITE, MAP_SHARED,fd,0);
|
||||
|
||||
// MallocCounter = (int)sz;
|
||||
// }
|
||||
|
||||
FUNCTION malloc(sz):
|
||||
sz = ALIGN_UP(sz, MAX_ALIGNMENT) // Align size to max alignment
|
||||
MallocCounter = MallocCounter - sz // Update remaining memory
|
||||
ptrLink = &ptr[MallocCounter] // Calculate pointer address
|
||||
ptrLink = SET_BOUNDS(ptrLink, sz) // Set bounds for memory safety and to track the length of the pointer
|
||||
RETURN ptrLink // Return allocated memory pointer
|
||||
|
||||
FUNCTION free(ptr):
|
||||
len = GET_LENGTH(ptr) // Get length of memory block from the defined bounds
|
||||
UNMAP(ptr, len) // Release memory block
|
||||
|
||||
FUNCTION Init_alloc():
|
||||
sz = 1 GB // Define pre-allocated memory size
|
||||
fd = CREATE_LARGE_PAGE_MEMORY(sz) // Create shared memory
|
||||
ptr = MAP_MEMORY(sz) // Map memory region
|
||||
MallocCounter = sz // Initialize memory counter
|
||||
@@ -0,0 +1,18 @@
|
||||
sh build.sh
|
||||
|
||||
LD_PRELOAD=./libjemalloc.so time pmcstat -d -w 1 -p l1d_tlb_rd -p l2d_tlb_rd -p l1d_tlb_refill -p cpu_cycles -p dtlb_walk -p stall_backend -p ll_cache_miss_rd -o kmeans-alloc-350000.txt ./kmeans-pthread.out -d 40 -c 100 -p 350000 -s 1000 > kmeans-bounds-350000-out.txt
|
||||
LD_PRELOAD=./libjemalloc.so time pmcstat -d -w 1 -p l1d_tlb_rd -p l2d_tlb_rd -p l1d_tlb_refill -p cpu_cycles -p dtlb_walk -p stall_backend -p ll_cache_miss_rd -o kmeans-alloc-300000.txt ./kmeans-pthread.out -d 40 -c 100 -p 300000 -s 1000 > kmeans-bounds-300000-out.txt
|
||||
LD_PRELOAD=./libjemalloc.so time pmcstat -d -w 1 -p l1d_tlb_rd -p l2d_tlb_rd -p l1d_tlb_refill -p cpu_cycles -p dtlb_walk -p stall_backend -p ll_cache_miss_rd -o kmeans-alloc-250000.txt ./kmeans-pthread.out -d 40 -c 100 -p 250000 -s 1000 > kmeans-bounds-250000-out.txt
|
||||
LD_PRELOAD=./libjemalloc.so time pmcstat -d -w 1 -p l1d_tlb_rd -p l2d_tlb_rd -p l1d_tlb_refill -p cpu_cycles -p dtlb_walk -p stall_backend -p ll_cache_miss_rd -o kmeans-alloc-200000.txt ./kmeans-pthread.out -d 40 -c 100 -p 200000 -s 1000 > kmeans-bounds-200000-out.txt
|
||||
LD_PRELOAD=./libjemalloc.so time pmcstat -d -w 1 -p l1d_tlb_rd -p l2d_tlb_rd -p l1d_tlb_refill -p cpu_cycles -p dtlb_walk -p stall_backend -p ll_cache_miss_rd -o kmeans-alloc-150000.txt ./kmeans-pthread.out -d 40 -c 100 -p 150000 -s 1000 > kmeans-bounds-150000-out.txt
|
||||
LD_PRELOAD=./libjemalloc.so time pmcstat -d -w 1 -p l1d_tlb_rd -p l2d_tlb_rd -p l1d_tlb_refill -p cpu_cycles -p dtlb_walk -p stall_backend -p ll_cache_miss_rd -o kmeans-alloc-100000.txt ./kmeans-pthread.out -d 40 -c 100 -p 100000 -s 1000 > kmeans-bounds-100000-out.txt
|
||||
|
||||
LD_PRELOAD=./regularjemalloc.so time pmcstat -d -w 1 -p l1d_tlb_rd -p l2d_tlb_rd -p l1d_tlb_refill -p cpu_cycles -p dtlb_walk -p stall_backend -p ll_cache_miss_rd -o kmeans-regular-alloc-350000.txt ./kmeans-pthread.out -d 40 -c 100 -p 350000 -s 1000 > kmeans-bounds-regular-350000-out.txt
|
||||
LD_PRELOAD=./regularjemalloc.so time pmcstat -d -w 1 -p l1d_tlb_rd -p l2d_tlb_rd -p l1d_tlb_refill -p cpu_cycles -p dtlb_walk -p stall_backend -p ll_cache_miss_rd -o kmeans-regular-alloc-300000.txt ./kmeans-pthread.out -d 40 -c 100 -p 300000 -s 1000 > kmeans-bounds-regular-300000-out.txt
|
||||
LD_PRELOAD=./regularjemalloc.so time pmcstat -d -w 1 -p l1d_tlb_rd -p l2d_tlb_rd -p l1d_tlb_refill -p cpu_cycles -p dtlb_walk -p stall_backend -p ll_cache_miss_rd -o kmeans-regular-alloc-250000.txt ./kmeans-pthread.out -d 40 -c 100 -p 250000 -s 1000 > kmeans-bounds-regular-250000-out.txt
|
||||
LD_PRELOAD=./regularjemalloc.so time pmcstat -d -w 1 -p l1d_tlb_rd -p l2d_tlb_rd -p l1d_tlb_refill -p cpu_cycles -p dtlb_walk -p stall_backend -p ll_cache_miss_rd -o kmeans-regular-alloc-200000.txt ./kmeans-pthread.out -d 40 -c 100 -p 200000 -s 1000 > kmeans-bounds-regular-200000-out.txt
|
||||
LD_PRELOAD=./regularjemalloc.so time pmcstat -d -w 1 -p l1d_tlb_rd -p l2d_tlb_rd -p l1d_tlb_refill -p cpu_cycles -p dtlb_walk -p stall_backend -p ll_cache_miss_rd -o kmeans-regular-alloc-150000.txt ./kmeans-pthread.out -d 40 -c 100 -p 150000 -s 1000 > kmeans-bounds-regular-150000-out.txt
|
||||
LD_PRELOAD=./regularjemalloc.so time pmcstat -d -w 1 -p l1d_tlb_rd -p l2d_tlb_rd -p l1d_tlb_refill -p cpu_cycles -p dtlb_walk -p stall_backend -p ll_cache_miss_rd -o kmeans-regular-alloc-100000.txt ./kmeans-pthread.out -d 40 -c 100 -p 100000 -s 1000 > kmeans-bounds-regular-100000-out.txt
|
||||
|
||||
# time pmcstat -d -w 1 -p l1d_tlb_rd -p l2d_tlb_rd -p l1d_tlb_refill -p cpu_cycles -p dtlb_walk -p stall_backend -p ll_cache_miss_rd -o kmeans-regular-alloc-10000.txt ./kmeans-pthread.out -d 40 -c 100 -p 10000 -s 1000 > kmeans-bounds-regular-10000-out.txt
|
||||
# time pmcstat -d -w 1 -p l1d_tlb_rd -p l2d_tlb_rd -p l1d_tlb_refill -p cpu_cycles -p dtlb_walk -p stall_backend -p ll_cache_miss_rd -o kmeans-regular-alloc-1000.txt ./kmeans-pthread.out -d 40 -c 100 -p 1000 -s 1000 > kmeans-bounds-regular-1000-out.txt
|
||||
177
allocator/testallocator/benchmarks/kmeans/simple.h
Normal file
177
allocator/testallocator/benchmarks/kmeans/simple.h
Normal file
@@ -0,0 +1,177 @@
|
||||
// /* Copyright (C) 2023. Shivashish Das. Licensed under the MIT License.*/
|
||||
// #include <stdint.h>
|
||||
// #include <stdlib.h>
|
||||
// #include <stdio.h>
|
||||
// #include <string.h>
|
||||
// #include <time.h>
|
||||
|
||||
// // source: https://www.reddit.com/r/C_Programming/comments/1bt8dyz/github_dasshivamalloc_a_simple_memory_allocator/
|
||||
|
||||
// // #include "alloc.h"
|
||||
// #ifndef _MSC_VER
|
||||
// #include <sys/mman.h>
|
||||
// #endif
|
||||
// /* This is a simple memory allocator meant for use in single threaded applications.
|
||||
// First we get memory from the system allocator which is defined by the pool size
|
||||
// Larger the pool size, more is the amount you can allocate before running out of memory.
|
||||
// On linux, mmap() is used for memory allocation while on windows good old calloc() is used as the system allocator
|
||||
|
||||
// Some basic definitions:
|
||||
// Block - A memory region always of size 16 bytes. This is the basic unit of allocation
|
||||
// All allocations are made in multiples of blocks. If any allocation request is not a multiple of 16 bytes, we return memory of a size
|
||||
// that is the closest multiple to 16 and greater than the user requested size.
|
||||
|
||||
// Metadata blocks - For every allocation we allocate two extra blocks. These two blocks hold data about the allocation itself
|
||||
// and serve to prevent buffer overflows too. Check the comment in alloc() to find out more. For example suppose that if the user asks for 80 bytes
|
||||
// i.e 80 / 16 = 5 blocks, we will allocate 7 blocks but the pointer passed to the user will point to the seconf block so the user is unable to access
|
||||
// these blocks. They do sound like a waste of some bytes but help provide protection from buffer overflows
|
||||
|
||||
// Posioning - This means that user code has overflown the buffer it was allocated. All memory allocated by alloc() is now invalid
|
||||
// However this may also be caused by the user simply passing an invalid pointer to us i.e a pointer allocated by some other allocator etc.
|
||||
// In this case the user can clear the poisoned state by calling clear_posion() but be absolutely sure as a user about this before doing so
|
||||
// */
|
||||
// static uint8_t* mem = 0;
|
||||
// static uint8_t* bitmap = 0;
|
||||
// static uint64_t blocks = 0;
|
||||
// static uint8_t poison = 0;
|
||||
|
||||
// // Always call this before anything else.
|
||||
// void alloc_init(uint64_t pool) {
|
||||
// if (pool % 16 != 0) {
|
||||
// int rem = pool % 16;
|
||||
// pool += (16 - rem);
|
||||
// }
|
||||
|
||||
// #ifndef _MSC_VER
|
||||
// mem = mmap(0, pool, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
// if (mem == MAP_FAILED) {
|
||||
// fprintf(stderr, "alloc_init(): could not allocate heap\n");
|
||||
// perror("mmap");
|
||||
// return;
|
||||
// }
|
||||
// #else
|
||||
// mem = calloc(pool, 1);
|
||||
// if (!mem) {
|
||||
// fprintf(stderr, "alloc_init(): could not allocate heap\n");
|
||||
// exit(1);
|
||||
// }
|
||||
// #endif
|
||||
// // Each bitmap entry can represent 8 blocks and each block is 16 bytes
|
||||
// // So space representable in one uint8_t is 16 * 8 = 128 bytes
|
||||
// uint64_t sz = pool / 128;
|
||||
// if (sz == 0)
|
||||
// sz = 1; // allocate at least one to keep track of small pools
|
||||
|
||||
// #ifndef _MSC_VER
|
||||
// bitmap = mmap(0, sz , PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
// if (bitmap == MAP_FAILED) {
|
||||
// fprintf(stderr, "alloc_init(): could not allocate bitmap");
|
||||
// munmap(mem, pool);
|
||||
// }
|
||||
// #else
|
||||
// bitmap = calloc(sz, 1);
|
||||
// if (!bitmap) {
|
||||
// fprintf(stderr, "alloc_init(): could not allocate bitmap\n");
|
||||
// exit(1);
|
||||
// }
|
||||
// #endif
|
||||
// // Zero the entire bitmap
|
||||
// memset(bitmap, 0, sz);
|
||||
// blocks = pool / 16;
|
||||
// }
|
||||
|
||||
// #define IS_FREE(blkid) (bitmap[blkid / 8] & (((uint8_t)1) << blkid)) == 0
|
||||
// #define MARK(blkid) (bitmap[blkid / 8] ^= ((((uint8_t)1) << blkid) - 1))
|
||||
|
||||
// // Allocate sz bytes of memory. Caution: May allocate upto 15 bytes more than sz
|
||||
// void* alloc(uint64_t sz) {
|
||||
// if (sz % 16 != 0) {
|
||||
// int rem = sz % 16;
|
||||
// sz += (16 - rem);
|
||||
// }
|
||||
// // Allocate two extra blocks
|
||||
// // First will be allocated at just behind the first user accessible block
|
||||
// // This block will have the number of blocks allocated and a randomly generated magic number each 8 bytes long
|
||||
// // The last block has the "magic number" present in the first block
|
||||
// // If this magic number gets modified then when free() tries to free the memory
|
||||
// // Buffer overruns will be caught and this allocator gets poisoned i.e it can no longer allocate memory
|
||||
// // This is because all blocks are laid out sequentially and if the user overruns the blocks allocated
|
||||
// // Then the user may have overwritten the contents of other blocks and it is not possible to estimate the damage caused
|
||||
// // and data corrupted. All pointers to blocks allocated immediately become invalid and free() posions the allocator
|
||||
// // This helps catch buffer overflows early on
|
||||
// uint64_t blk = (sz / 16) + 2;
|
||||
|
||||
// // if we are posioned, all allocation requests will fail
|
||||
// if (poison)
|
||||
// return 0;
|
||||
// // Loop through the entire bitmap. If a free block is found, check if there are at least blk free blocks after it.
|
||||
// // If such a contigious group of blocks is found, take appropriate actions and return to user
|
||||
// // Otherwise we have ran out of memory so inform the user about it
|
||||
// for (uint64_t i = 0; i < blocks; i++) {
|
||||
// if (IS_FREE(i)) {
|
||||
// // Check for contigious free blocks
|
||||
// for (uint64_t j = i; j < (i + blk); j++) {
|
||||
// if (!IS_FREE(j))
|
||||
// goto next;
|
||||
// }
|
||||
|
||||
// // Mark all free blocks
|
||||
// for (uint64_t j = i; j < (i + blk + 1); j++) {
|
||||
// MARK(j);
|
||||
// }
|
||||
// uint64_t* ptr = mem + (i * 16);
|
||||
// *ptr = blk;
|
||||
|
||||
// // I needed a number which was large enough to occupy 8 bytes so rand() is not enough as in most cases RAND_MAX is only USHORT_MAX
|
||||
// // Instead use time() which returns a 64 bit value and is almost guaranteed to be unique on every call to alloc()
|
||||
// uint64_t magic = time(0);
|
||||
// *(ptr + 1) = magic;
|
||||
|
||||
// // Store a magic number in the last block. For the reason see free_mem()
|
||||
// ptr = mem + (i * 16) + ((blk - 1) * 16);
|
||||
// *ptr = magic;
|
||||
// *(ptr + 1) = magic;
|
||||
// // Return the user a pointer which points to the region just above our metadata block
|
||||
// return mem + ((i + 1) * 16);
|
||||
// }
|
||||
// next:
|
||||
// }
|
||||
// fprintf(stderr, "Pool has been exhausted...Cannot allocate more memory");
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// // Frees memory allocated by alloc()
|
||||
// void free_mem(void* data) {
|
||||
// // First get the number of blocks allocated and magic from the metadata block (i.e the block right behind what alloc() returned)
|
||||
// uint64_t* ptr = data;
|
||||
// ptr -= 2;
|
||||
// uint64_t blk = *ptr;
|
||||
// ptr++;
|
||||
// uint64_t magic = *ptr;
|
||||
|
||||
// // The magic is stored in the last block of the allocation
|
||||
// // Compare the two magic values
|
||||
// // If they are equal, this memory block was allocated by us and we can free this
|
||||
// // Otherwise the buffer has been overflown which has overwritten the magic number or this was not allocated by alloc() and is not ours to deal with
|
||||
// ptr = data + (blk - 2) * 16;
|
||||
// if (magic != *ptr) {
|
||||
// // If the buffer has overflown then mark this allocator posioned.
|
||||
// // You may change the poison back to 0 in your code but be careful and do this only if you know that the buffer was not overrun
|
||||
// fprintf(stderr, "Invalid pointer or buffer overrun detected..Poisoning ourself");
|
||||
// poison = 1;
|
||||
// return;
|
||||
// }
|
||||
// uint64_t offset = ((uint8_t*) data) - mem;
|
||||
// offset -= 16;
|
||||
// offset /= 16;
|
||||
|
||||
// // Clear all bits representing this block so next call to alloc() can use this
|
||||
// for (uint64_t j = offset; j < offset + blk + 1; j++) {
|
||||
// MARK(j);
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Do not call this unless you are absolutely sure about the cause of poisoning
|
||||
// void clear_posion() {
|
||||
// poison = 0;
|
||||
// }
|
||||
298
allocator/testallocator/benchmarks/kmeans/stddefines.h
Normal file
298
allocator/testallocator/benchmarks/kmeans/stddefines.h
Normal file
@@ -0,0 +1,298 @@
|
||||
/* Copyright (c) 2007-2009, Stanford University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Stanford University nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef STDDEFINES_H_
|
||||
#define STDDEFINES_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <cheriintrin.h>
|
||||
#include <cheri/cheric.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define MAXPAGESIZES 2
|
||||
|
||||
|
||||
//#define TIMING
|
||||
|
||||
/* Debug printf */
|
||||
#define dprintf(...) fprintf(stdout, __VA_ARGS__)
|
||||
|
||||
/* Wrapper to check for errors */
|
||||
#define CHECK_ERROR(a) \
|
||||
if (a) \
|
||||
{ \
|
||||
perror("Error at line\n\t" #a "\nSystem Msg"); \
|
||||
assert ((a) == 0); \
|
||||
}
|
||||
|
||||
static inline void *MALLOC(size_t size)
|
||||
{
|
||||
void * temp = malloc(size);
|
||||
assert(temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
static inline void *CALLOC(size_t num, size_t size)
|
||||
{
|
||||
void * temp = calloc(num, size);
|
||||
assert(temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
static inline void *REALLOC(void *ptr, size_t size)
|
||||
{
|
||||
void * temp = realloc(ptr, size);
|
||||
assert(temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
static inline char *GETENV(char *envstr)
|
||||
{
|
||||
char *env = getenv(envstr);
|
||||
if (!env) return "0";
|
||||
else return env;
|
||||
}
|
||||
|
||||
#define GET_TIME(start, end, duration) \
|
||||
duration.tv_sec = (end.tv_sec - start.tv_sec); \
|
||||
if (end.tv_nsec >= start.tv_nsec) { \
|
||||
duration.tv_nsec = (end.tv_nsec - start.tv_nsec); \
|
||||
} \
|
||||
else { \
|
||||
duration.tv_nsec = (1000000000L - (start.tv_nsec - end.tv_nsec)); \
|
||||
duration.tv_sec--; \
|
||||
} \
|
||||
if (duration.tv_nsec >= 1000000000L) { \
|
||||
duration.tv_sec++; \
|
||||
duration.tv_nsec -= 1000000000L; \
|
||||
}
|
||||
|
||||
static inline unsigned int time_diff (
|
||||
struct timeval *end, struct timeval *begin)
|
||||
{
|
||||
#ifdef TIMING
|
||||
uint64_t result;
|
||||
|
||||
result = end->tv_sec - begin->tv_sec;
|
||||
result *= 1000000; /* usec */
|
||||
result += end->tv_usec - begin->tv_usec;
|
||||
|
||||
return result;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void get_time (struct timeval *t)
|
||||
{
|
||||
#ifdef TIMING
|
||||
gettimeofday (t, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Expirement work
|
||||
|
||||
#define FILENAME "/dev/contigmem"
|
||||
|
||||
static char *heap_start;
|
||||
static char *heap;
|
||||
static size_t HEAP_SIZE = 1024 * 1024 * 1024;
|
||||
|
||||
void *ptr;
|
||||
int MallocCounter;
|
||||
|
||||
size_t sizeUsed;
|
||||
|
||||
INITAlloc(void) {
|
||||
|
||||
size_t sz;
|
||||
// Pre Allocate 600 MB
|
||||
sz = 100000000;
|
||||
|
||||
int fd = open(FILENAME, O_RDWR, 0600);
|
||||
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
off_t offset = 0; // offset to seek to.
|
||||
|
||||
if (ftruncate(fd, sz) < 0) {
|
||||
perror("ftruncate");
|
||||
close(fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// ptr = mmap(NULL, sz,
|
||||
// PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON,-1,0);
|
||||
|
||||
ptr = mmap(NULL, sz,
|
||||
PROT_READ|PROT_WRITE, MAP_SHARED,fd,0);
|
||||
|
||||
// Added error handling
|
||||
if(ptr == MAP_FAILED)
|
||||
{
|
||||
perror("mmap");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
MallocCounter = (int)sz;
|
||||
|
||||
}
|
||||
|
||||
// Quick malloc implementation with mmap
|
||||
void* MALLOCCHERI(size_t sz)
|
||||
{
|
||||
sz = __builtin_align_up(sz, _Alignof(max_align_t));
|
||||
|
||||
// printf("%d \n", sz);
|
||||
// printf("%d Malloc counter\n", MallocCounter);
|
||||
|
||||
MallocCounter -= sz;
|
||||
void *ptrLink = &ptr[MallocCounter];
|
||||
ptrLink = cheri_setbounds(ptrLink, sz);
|
||||
|
||||
return ptrLink;
|
||||
|
||||
// if (heap + sz > heap_start + HEAP_SIZE) return NULL;
|
||||
// heap += sz;
|
||||
// return heap - sz;
|
||||
|
||||
}
|
||||
|
||||
// Quick cheri free implementation
|
||||
void FREECHERI(void *ptr) {
|
||||
|
||||
// printf("free called \n");
|
||||
|
||||
// get bounds from
|
||||
int len = cheri_getlen(ptr);
|
||||
|
||||
// printf("free len %d \n", len);
|
||||
|
||||
munmap(ptr, len);
|
||||
}
|
||||
|
||||
static int
|
||||
pagesizes(size_t ps[MAXPAGESIZES])
|
||||
{
|
||||
int pscnt;
|
||||
|
||||
pscnt = getpagesizes(ps, MAXPAGESIZES);
|
||||
// ATF_REQUIRE_MSG(pscnt != -1, "getpagesizes failed; errno=%d", errno);
|
||||
// ATF_REQUIRE_MSG(ps[0] != 0, "psind 0 is %zu", ps[0]);
|
||||
// ATF_REQUIRE_MSG(pscnt <= MAXPAGESIZES, "invalid pscnt %d", pscnt);
|
||||
// if (pscnt == 1){
|
||||
// printf("pscnt is 1");
|
||||
// }
|
||||
|
||||
// atf_tc_skip("no large page support");
|
||||
return (pscnt);
|
||||
}
|
||||
|
||||
INITREGULARALLOC(void) {
|
||||
size_t sz;
|
||||
// Pre Allocate 400 MB
|
||||
sz = 1073741824;
|
||||
|
||||
int error, fd, pscnt, pn;
|
||||
|
||||
size_t ps[MAXPAGESIZES];
|
||||
|
||||
size_t size[3];
|
||||
|
||||
pn = getpagesizes(size, 3);
|
||||
printf("page size is [%d]", size[2]);
|
||||
|
||||
pscnt = pagesizes(ps);
|
||||
|
||||
fd = shm_create_largepage(SHM_ANON, O_CREAT | O_RDWR, 1, SHM_LARGEPAGE_ALLOC_DEFAULT, 0);
|
||||
|
||||
if (fd < 0 && errno == ENOTTY) {
|
||||
perror("sh_create_largepages");
|
||||
close(fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// if (fd < 0)
|
||||
// perror("no large page supported");
|
||||
// exit(EXIT_FAILURE);
|
||||
// if (fd < 0 && errno == ENOTTY)
|
||||
// atf_tc_skip("no large page support");
|
||||
// ATF_REQUIRE_MSG(fd >= 0, "shm_create_largepage failed; errno=%d", errno);
|
||||
|
||||
if (ftruncate(fd, sz) < 0) {
|
||||
perror("ftruncate");
|
||||
close(fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// if (error != 0 && errno == ENOMEM)
|
||||
// /*
|
||||
// * The test system might not have enough memory to accommodate
|
||||
// * the request.
|
||||
// */
|
||||
// atf_tc_skip("failed to allocate %zu-byte superpage", sz);
|
||||
// ATF_REQUIRE_MSG(error == 0, "ftruncate failed; errno=%d", errno);
|
||||
|
||||
ptr = mmap(NULL, sz,
|
||||
PROT_READ|PROT_WRITE, MAP_SHARED,fd,0);
|
||||
|
||||
// Added error handling
|
||||
if(ptr == MAP_FAILED)
|
||||
{
|
||||
perror("mmap");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
MallocCounter = (int)sz;
|
||||
}
|
||||
// Standard Alloc
|
||||
// void* MALLOCREGULAR(size_t sz) {
|
||||
|
||||
// }
|
||||
|
||||
|
||||
// void* CLEARALLOC(void) {
|
||||
// /
|
||||
// }
|
||||
|
||||
#endif // STDDEFINES_H_
|
||||
@@ -1,7 +1,7 @@
|
||||
# build glibc
|
||||
cc -g -Wall -o glibc-bench.out -march=morello -mabi=purecap -Xclang -morello-vararg=new -lpthread glibc.c
|
||||
cc -g -Wall -o glibc-bench.out -march=morello -mabi=purecap -Xclang -morello-vararg=new -lpthread simple_c.c
|
||||
|
||||
# build shared object library
|
||||
cc -O3 -g -W -Wall -shared -o ./malloc.so -mabi=purecap -Wno-unused-parameter -lpthread -fPIC alloc.c
|
||||
cc -O3 -g -W -Wall -shared -o ./malloc.so -mabi=purecap -Wno-unused-parameter -lpthread -fPIC allocBitmap.c
|
||||
|
||||
LD_PRELOAD=malloc.so ./glibc-bench.out
|
||||
|
||||
175
allocator/testallocator/custom_alloc.h
Normal file
175
allocator/testallocator/custom_alloc.h
Normal file
@@ -0,0 +1,175 @@
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <cheriintrin.h>
|
||||
#include <cheri/cheric.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MAXPAGESIZES 2
|
||||
|
||||
static char *heap_start;
|
||||
static char *heap;
|
||||
static size_t HEAP_SIZE = 1024 * 1024 * 1024;
|
||||
|
||||
void *ptr;
|
||||
int MallocCounter;
|
||||
int malloc_called = 0;
|
||||
|
||||
size_t sizeUsed;
|
||||
|
||||
// Instrcutor allocator to create the huge page
|
||||
// of 1 GB
|
||||
// __attribute__((constructor))
|
||||
static void INITREGULARALLOC() {
|
||||
size_t sz;
|
||||
// Hard-coded for 1GB huge page
|
||||
sz = 1073741824;
|
||||
|
||||
int error, fd, pscnt, pn;
|
||||
|
||||
size_t ps[2];
|
||||
|
||||
size_t size[3];
|
||||
|
||||
// pn = getpagesizes(size, 3);
|
||||
// printf("page size is [%d]", size[2]);
|
||||
|
||||
// pscnt = pagesizes(ps);
|
||||
|
||||
fd = shm_create_largepage(SHM_ANON, O_CREAT | O_RDWR, 1, SHM_LARGEPAGE_ALLOC_DEFAULT, 0);
|
||||
|
||||
if (fd < 0 && errno == ENOTTY) {
|
||||
perror("sh_create_largepages");
|
||||
close(fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// if (fd < 0)
|
||||
// perror("no large page supported");
|
||||
// exit(EXIT_FAILURE);
|
||||
// if (fd < 0 && errno == ENOTTY)
|
||||
// atf_tc_skip("no large page support");
|
||||
// ATF_REQUIRE_MSG(fd >= 0, "shm_create_largepage failed; errno=%d", errno);
|
||||
|
||||
if (ftruncate(fd, sz) < 0) {
|
||||
perror("ftruncate");
|
||||
close(fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// if (error != 0 && errno == ENOMEM)
|
||||
// /*
|
||||
// * The test system might not have enough memory to accommodate
|
||||
// * the request.
|
||||
// */
|
||||
// atf_tc_skip("failed to allocate %zu-byte superpage", sz);
|
||||
// ATF_REQUIRE_MSG(error == 0, "ftruncate failed; errno=%d", errno);
|
||||
|
||||
ptr = mmap(NULL, sz,
|
||||
PROT_READ|PROT_WRITE, MAP_SHARED,fd,0);
|
||||
|
||||
// Added error handling
|
||||
if(ptr == MAP_FAILED)
|
||||
{
|
||||
perror("mmap");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
// fprintf(stderr, "heap used alloc %lu\n", heap - heap_start);
|
||||
|
||||
MallocCounter = (int)sz;
|
||||
}
|
||||
|
||||
// -- Custom malloc and free functions written
|
||||
// This will be replaced with mmap since we already
|
||||
// do a initial mmap.
|
||||
|
||||
int notrun1 = 0;
|
||||
|
||||
void *MALLOCCHERI(size_t sz)
|
||||
{
|
||||
if (notrun1 == 0){
|
||||
INITREGULARALLOC();
|
||||
notrun1 = 1;
|
||||
}
|
||||
|
||||
sz = __builtin_align_up(sz, _Alignof(max_align_t));
|
||||
|
||||
// printf("%d \n", sz);
|
||||
// printf("%d Malloc counter\n", MallocCounter);
|
||||
|
||||
MallocCounter -= sz;
|
||||
void *ptrLink = &ptr[MallocCounter];
|
||||
ptrLink = cheri_setbounds(ptrLink, sz);
|
||||
|
||||
return ptrLink;
|
||||
|
||||
// if (heap + sz > heap_start + HEAP_SIZE) return NULL;
|
||||
// heap += sz;
|
||||
// return heap - sz;
|
||||
|
||||
}
|
||||
|
||||
// Quick cheri free implementation
|
||||
void FREECHERI(void *ptr) {
|
||||
|
||||
// printf("free called \n");
|
||||
|
||||
// get bounds from
|
||||
int len = cheri_getlen(ptr);
|
||||
|
||||
// printf("free len %d \n", len);
|
||||
|
||||
munmap(ptr, len);
|
||||
}
|
||||
|
||||
__attribute__((destructor))
|
||||
static void malloc_exit() {
|
||||
fprintf(stderr, "heap used %lu\n", malloc_called);
|
||||
}
|
||||
|
||||
// void *malloc(size_t sz) {
|
||||
// // if (!heap) heap = heap_start = mmap(NULL, HEAP_SIZE,
|
||||
// // PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON,-1,0);
|
||||
|
||||
// // char *new_ptr = __builtin_align_up(
|
||||
// // heap, -cheri_representable_alignment_mask(sz));
|
||||
// // size_t bounds = cheri_representable_length(sz);
|
||||
// // sz = __builtin_align_up(sz, _Alignof(max_align_t));
|
||||
|
||||
// // if (new_ptr + sz > heap_start + HEAP_SIZE)
|
||||
// // return NULL;
|
||||
// // heap = new_ptr + sz;
|
||||
// // return cheri_bounds_set_exact(new_ptr, bounds);
|
||||
// return MALLOCCHERI(sz);
|
||||
// }
|
||||
|
||||
// void *malloc(size_t sz) {
|
||||
// // if (!heap) heap = heap_start = mmap(NULL, HEAP_SIZE,
|
||||
// // PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON,-1,0);
|
||||
// // sz = __builtin_align_up(sz, _Alignof(max_align_t));
|
||||
// // if (heap + sz > heap_start + HEAP_SIZE) return NULL;
|
||||
// // heap += sz;
|
||||
// // return heap - sz;
|
||||
// malloc_called += 1;
|
||||
// return MALLOCCHERI(sz);
|
||||
// }
|
||||
|
||||
// void free(void *ptr) {
|
||||
// FREECHERI(ptr);
|
||||
// }
|
||||
@@ -206,7 +206,7 @@ main (int argc, char **argv)
|
||||
usage (argv[0]);
|
||||
|
||||
// bench (size);
|
||||
bench (2*size);
|
||||
bench (size);
|
||||
printf("done");
|
||||
//bench (4*size);
|
||||
//bench (8*size);
|
||||
|
||||
215
allocator/testallocator/regularBitmapalloc.c
Normal file
215
allocator/testallocator/regularBitmapalloc.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/**********************************
|
||||
* 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.
|
||||
|
||||
int notrun = 0;
|
||||
|
||||
void *malloc(size_t len)
|
||||
{
|
||||
if (notrun == 0){
|
||||
init_alloc(500,1000);
|
||||
notrun = 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
40
allocator/testallocator/simple_c.c
Normal file
40
allocator/testallocator/simple_c.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
int *ptr;
|
||||
int n, i;
|
||||
|
||||
printf("Enter the number of elements: ");
|
||||
scanf("%d", &n);
|
||||
// Allocate memory for n integers
|
||||
ptr = (int *)malloc(n * sizeof(int));
|
||||
|
||||
// Check if memory has been successfully allocated
|
||||
if (ptr == NULL) {
|
||||
printf("Memory not allocated.\n");
|
||||
return 1; // Exit the program
|
||||
}
|
||||
|
||||
// Memory has been successfully allocated
|
||||
printf("Memory successfully allocated using malloc.\n");
|
||||
|
||||
// Get the elements
|
||||
for (i = 0; i < n; i++) {
|
||||
printf("Enter element %d: ", i + 1);
|
||||
scanf("%d", &ptr[i]);
|
||||
}
|
||||
|
||||
// Print the elements
|
||||
printf("The elements are: ");
|
||||
for (i = 0; i < n; i++) {
|
||||
printf("%d ", ptr[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// Free the allocated memory
|
||||
free(ptr);
|
||||
printf("Memory successfully freed.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user