added test alloc with working purecap

This commit is contained in:
2025-04-07 17:10:55 +01:00
parent 4894364ddf
commit 8cf048b6b2
5 changed files with 465 additions and 10 deletions

View File

@@ -0,0 +1,225 @@
#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 notrun = 0;
void *MALLOCCHERI(size_t sz)
{
if (notrun == 0){
INITREGULARALLOC();
notrun = 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);
}
void *realloc(void *ptr, size_t sz) {
void *new_ptr = malloc(sz);
if (ptr && new_ptr) memmove(new_ptr, ptr, sz);
return new_ptr;
}
void *calloc(size_t nmemb, size_t sz) {
char *ptr = malloc(nmemb * sz);
bzero(ptr, nmemb * sz);
return ptr;
}
void *reallocarray(void *ptr, size_t nmemb, size_t sz) {
return realloc(ptr, nmemb * sz);
}
void *recallocarray(void *ptr, size_t oldnmemb, size_t nmemb, size_t sz) {
void *new_ptr = malloc(nmemb * sz);
if (ptr && new_ptr) memmove(new_ptr, ptr, oldnmemb * sz);
if (new_ptr && nmemb > oldnmemb) bzero(new_ptr + oldnmemb * sz, (nmemb - oldnmemb) * sz);
return new_ptr;
}
void freezero(void *ptr, size_t sz) { }
void *aligned_alloc(size_t alignment, size_t sz) {
return malloc(sz);
}
void *malloc_conceal(size_t sz) {
return malloc(sz);
}
void *calloc_conceal(size_t nmemb, size_t sz) {
return calloc(nmemb, sz);
}
int posix_memalign(void **ptr, size_t alignment, size_t sz) {
*ptr = malloc(sz);
return *ptr == 0 ? 0 : ENOMEM;
}
void *memalign(size_t alignment, size_t sz) {
return malloc(sz);
}
void *valloc(size_t sz) {
return malloc(sz);
}

View File

@@ -0,0 +1,7 @@
# build glibc
cc -g -Wall -o glibc-bench.out -march=morello -mabi=purecap -Xclang -morello-vararg=new -lpthread glibc.c
# build shared object library
cc -O3 -g -W -Wall -shared -o ./malloc.so -mabi=purecap -Wno-unused-parameter -lpthread -fPIC alloc.c
LD_PRELOAD=malloc.so ./glibc-bench.out

View File

@@ -0,0 +1,217 @@
/* Benchmark malloc and free functions.
Copyright (C) 2019-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
// modified by Daan Leijen to fit the bench suite and add lifo/fifo free order.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
//#include "malloc.h"
// #define malloc MALLOCCHERI
// #define free FREECHERI
// #include "bench-timing.h"
// #include "json-lib.h"
/* Benchmark the malloc/free performance of a varying number of blocks of a
given size. This enables performance tracking of the t-cache and fastbins.
It tests 3 different scenarios: single-threaded using main arena,
multi-threaded using thread-arena, and main arena with SINGLE_THREAD_P
false. */
// source: https://github.com/daanx/mimalloc-bench/blob/master/bench/glibc-bench/bench-malloc-thread.c
#define NUM_ITERS 2000000
#define NUM_ALLOCS 4
#define MAX_ALLOCS 1600
// Daan: disable timing
typedef long timing_t;
#define TIMING_NOW(s)
#define TIMING_DIFF(e,start,stop)
typedef struct
{
size_t iters;
size_t size;
int n;
timing_t elapsed;
} malloc_args;
static void
do_benchmark (malloc_args *args, char**arr)
{
timing_t start, stop;
size_t iters = args->iters;
size_t size = args->size;
int n = args->n;
TIMING_NOW (start);
for (int j = 0; j < iters; j++)
{
for (int i = 0; i < n; i++) {
arr[i] = malloc (size);
for(int g = 0; g < size; g++) { arr[i][g] =(char)g; }
}
// free half in fifo order
for (int i = 0; i < n/2; i++) {
free (arr[i]);
}
// and the other half in lifo order
for(int i = n-1; i >= n/2; i--) {
free(arr[i]);
}
}
TIMING_NOW (stop);
TIMING_DIFF (args->elapsed, start, stop);
}
static malloc_args tests[3][NUM_ALLOCS];
static int allocs[NUM_ALLOCS] = { 25, 100, 400, MAX_ALLOCS };
static void *
thread_test (void *p)
{
char **arr = (char**)p;
/* Run benchmark multi-threaded. */
for (int i = 0; i < NUM_ALLOCS; i++)
do_benchmark (&tests[2][i], arr);
return p;
}
void
bench (unsigned long size)
{
size_t iters = NUM_ITERS;
char**arr = (char**)malloc (MAX_ALLOCS * sizeof (void*));
for (int t = 0; t < 3; t++)
for (int i = 0; i < NUM_ALLOCS; i++)
{
tests[t][i].n = allocs[i];
tests[t][i].size = size;
tests[t][i].iters = iters / allocs[i];
/* Do a quick warmup run. */
if (t == 0)
do_benchmark (&tests[0][i], arr);
}
/* Run benchmark single threaded in main_arena. */
for (int i = 0; i < NUM_ALLOCS; i++)
do_benchmark (&tests[0][i], arr);
/* Run benchmark in a thread_arena. */
pthread_t t;
pthread_create (&t, NULL, thread_test, (void*)arr);
pthread_join (t, NULL);
/* Repeat benchmark in main_arena with SINGLE_THREAD_P == false. */
for (int i = 0; i < NUM_ALLOCS; i++)
do_benchmark (&tests[1][i], arr);
free (arr);
/*
json_ctx_t json_ctx;
json_init (&json_ctx, 0, stdout);
json_document_begin (&json_ctx);
json_attr_string (&json_ctx, "timing_type", TIMING_TYPE);
json_attr_object_begin (&json_ctx, "functions");
json_attr_object_begin (&json_ctx, "malloc");
char s[100];
double iters2 = iters;
json_attr_object_begin (&json_ctx, "");
json_attr_double (&json_ctx, "malloc_block_size", size);
struct rusage usage;
getrusage (RUSAGE_SELF, &usage);
json_attr_double (&json_ctx, "max_rss", usage.ru_maxrss);
for (int i = 0; i < NUM_ALLOCS; i++)
{
sprintf (s, "main_arena_st_allocs_%04d_time", allocs[i]);
json_attr_double (&json_ctx, s, tests[0][i].elapsed / iters2);
}
for (int i = 0; i < NUM_ALLOCS; i++)
{
sprintf (s, "main_arena_mt_allocs_%04d_time", allocs[i]);
json_attr_double (&json_ctx, s, tests[1][i].elapsed / iters2);
}
for (int i = 0; i < NUM_ALLOCS; i++)
{
sprintf (s, "thread_arena__allocs_%04d_time", allocs[i]);
json_attr_double (&json_ctx, s, tests[2][i].elapsed / iters2);
}
json_attr_object_end (&json_ctx);
json_attr_object_end (&json_ctx);
json_attr_object_end (&json_ctx);
json_document_end (&json_ctx);
*/
}
static void usage (const char *name)
{
fprintf (stderr, "%s: <alloc_size>\n", name);
exit (1);
}
int
main (int argc, char **argv)
{
//INITREGULARALLOC();
long size = 16;
if (argc == 2)
size = strtol (argv[1], NULL, 0);
if (argc > 2 || size <= 0)
usage (argv[0]);
// bench (size);
bench (2*size);
printf("done");
//bench (4*size);
//bench (8*size);
// bench (16*size);
// bench (32*size);
return 0;
}