diff --git a/repos/ealanos/run/larson.run b/repos/ealanos/run/larson.run new file mode 100644 index 0000000000..bb25b652ca --- /dev/null +++ b/repos/ealanos/run/larson.run @@ -0,0 +1,60 @@ +set build_components { + core init hoitaja timer lib/ld lib/vfs lib/libm lib/libc lib/stdcxx bench/larson +} + +build $build_components +create_boot_directory + +install_config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2022-07-20 14:30 + + + + + + + +} + +build_boot_image [build_artifacts] + +append qemu_args " -nographic " +run_genode_until forever \ No newline at end of file diff --git a/repos/ealanos/src/bench/larson/README.md b/repos/ealanos/src/bench/larson/README.md new file mode 100644 index 0000000000..58694c31f3 --- /dev/null +++ b/repos/ealanos/src/bench/larson/README.md @@ -0,0 +1,4 @@ +Test driver for memory allocators +Author: Paul Larson, palarson@microsoft.com + +Updated to support C++14 sized deallocation with CPP. diff --git a/repos/ealanos/src/bench/larson/larson.cpp b/repos/ealanos/src/bench/larson/larson.cpp new file mode 100644 index 0000000000..9e8536711a --- /dev/null +++ b/repos/ealanos/src/bench/larson/larson.cpp @@ -0,0 +1,870 @@ + +#if defined(USE_HOARD) && defined(_WIN32) +#pragma comment(lib, "libhoard.lib") +#endif + +#if defined(USE_RX) && defined(_WIN32) +#pragma comment(lib, "libmi.lib") +#endif + +#include +#include +#include + +#if defined(_WIN32) +#define __WIN32__ +#endif + +#ifdef __WIN32__ +#include +#include +#include + +#else +#include +#include +#include + +#ifndef __SVR4 +//extern "C" int pthread_setconcurrency (int) throw(); +#include +#endif + +#include +#include +#include +#include +#include + +typedef void * LPVOID; +typedef long long LONGLONG; +typedef long DWORD; +typedef long LONG; +typedef unsigned long ULONG; +typedef union _LARGE_INTEGER { + struct { + DWORD LowPart; + LONG HighPart; + } foo; + LONGLONG QuadPart; // In Visual C++, a typedef to _ _int64} LARGE_INTEGER; +} LARGE_INTEGER; +typedef long long _int64; +#ifndef TRUE +enum { TRUE = 1, FALSE = 0 }; +#endif +#include +#define _ASSERTE(x) assert(x) +#define _inline inline +void Sleep (long x) +{ + // printf ("sleeping for %ld seconds.\n", x/1000); + sleep(x/1000); +} + +void QueryPerformanceCounter (long * x) +{ + struct timezone tz; + struct timeval tv; + gettimeofday (&tv, &tz); + *x = tv.tv_sec * 1000000L + tv.tv_usec; +} + +void QueryPerformanceFrequency(long * x) +{ + *x = 1000000L; +} + + +#include +#include +#include +#include +#include +#include +#include + +#define _REENTRANT 1 +#include +#ifdef __sun +#include +#endif +typedef void * VoidFunction (void *); +void _beginthread (VoidFunction x, int, void * z) +{ + pthread_t pt; + pthread_attr_t pa; + pthread_attr_init (&pa); + +#if 1//defined(__SVR4) + pthread_attr_setscope (&pa, PTHREAD_SCOPE_SYSTEM); /* bound behavior */ +#endif + + // printf ("creating a thread.\n"); + [[maybe_unused]] int v = pthread_create(&pt, &pa, x, z); + // printf ("v = %d\n", v); +} +#endif + + +#if 0 +static char buf[65536]; + +#define malloc(v) &buf +#define free(p) +#endif + +//#undef CPP +//#define CPP +//#include "arch-specific.h" + +#if USE_ROCKALL +//#include "FastHeap.hpp" +//FAST_HEAP theFastHeap (1024 * 1024, true, true, true); + +typedef int SBIT32; + +#include "SmpHeap.hpp" +SMP_HEAP theFastHeap (1024 * 1024, true, true, true); + +void * operator new( unsigned int cb ) +{ + void *pRet = theFastHeap.New ((size_t)cb) ; + return pRet; +} + +void operator delete[](void *pUserData ) +{ + theFastHeap.Delete (pUserData) ; +} +#endif + +#if 0 +extern "C" void * hdmalloc (size_t sz) ; +extern "C" void hdfree (void * ptr) ; +extern "C" void hdmalloc_stats (void) ; +void * operator new( unsigned int cb ) +{ + void *pRet = hdmalloc((size_t)cb) ; + return pRet; +} + +void operator delete[](void *pUserData ) +{ + hdfree(pUserData) ; +} +#endif + +#ifndef CUSTOM_MALLOC +#define CUSTOM_MALLOC malloc //_alloc->alloc +#define CUSTOM_FREE free //_alloc->free +#endif + + +/* Test driver for memory allocators */ +/* Author: Paul Larson, palarson@microsoft.com */ +#define MAX_THREADS 100 +#define MAX_BLOCKS 1000000 + +int volatile stopflag=FALSE ; + +struct lran2_st { + long x, y, v[97]; +}; + +int TotalAllocs=0 ; + +typedef struct thr_data { + + int threadno ; + int NumBlocks ; + int seed ; + + int min_size ; + int max_size ; + + char * *array ; + size_t *blksize ; + int asize ; + + long cAllocs ; + long cFrees ; + long cThreads ; + long cBytesAlloced ; + + volatile int finished ; + struct lran2_st rgen ; + +} thread_data; + +void runthreads(long sleep_cnt, int min_threads, int max_threads, + int chperthread, int num_rounds) ; +void runloops(long sleep_cnt, int num_chunks ) ; +static void warmup(char **blkp, int num_chunks ); +static void * exercise_heap( void *pinput) ; +static void lran2_init(struct lran2_st* d, long seed) ; +static long lran2(struct lran2_st* d) ; +ULONG CountReservedSpace() ; + +char * blkp[MAX_BLOCKS] ; +size_t blksize[MAX_BLOCKS] ; +long seqlock=0 ; +struct lran2_st rgen ; +int min_size=10, max_size=500 ; +int num_threads ; +ULONG init_space ; + +extern int cLockSleeps ; +extern int cAllocedChunks ; +extern int cAllocedSpace ; +extern int cUsedSpace ; +extern int cFreeChunks ; +extern int cFreeSpace ; + +int cChecked=0 ; + +using Allocator = Ealan::Memory::Hamstraaja<64, 512*2048>; +Allocator *_alloc{nullptr}; + +Libc::Env *_env{nullptr}; + +int main (int argc, char *argv[]) +{ + +#if defined(USE_LFH) && defined(_WIN32) + // Activate 'Low Fragmentation Heap'. + ULONG info = 2; + HeapSetInformation (GetProcessHeap(), + HeapCompatibilityInformation, + &info, + sizeof(info)); +#endif +#if 0 // defined(__SVR4) + { + psinfo_t ps; + int pid = getpid(); + char fname[255]; + sprintf (fname, "/proc/%d/psinfo", pid); + // sprintf (fname, "/proc/self/ps"); + FILE * f = fopen (fname, "rb"); + printf ("opening %s\n", fname); + if (f) { + fread (&ps, sizeof(ps), 1, f); + printf ("resident set size = %dK\n", ps.pr_rssize); + fclose (f); + } + } +#endif + + // char * dummy = new char[42]; + //ReferenceLibHoard(); +#if defined(_MT) || defined(_REENTRANT) + int min_threads, max_threads ; + int num_rounds ; + int chperthread ; +#endif + unsigned seed=12345 ; + int num_chunks=10000; + long sleep_cnt; + + if (argc > 7) { + sleep_cnt = atoi(argv[1]); + min_size = atoi(argv[2]); + max_size = atoi(argv[3]); + chperthread = atoi(argv[4]); + num_rounds = atoi(argv[5]); + seed = atoi(argv[6]); + max_threads = atoi(argv[7]); + min_threads = atoi(argv[8]); + goto DoneWithInput; + } + +#if defined(_MT) || defined(_REENTRANT) + //#ifdef _MT + printf( "\nMulti-threaded test driver \n") ; +#else + printf( "\nSingle-threaded test driver \n") ; +#endif +#ifdef CPP +#if defined(SIZED) + printf("C++ version (new and sized delete)\n") ; +#else + printf("C++ version (new and delete)\n") ; +#endif +#else + printf("C version (malloc and free)\n") ; +#endif + printf("runtime (sec): ") ; + scanf ("%ld", &sleep_cnt); + + printf("chunk size (min,max): ") ; + scanf("%d %d", &min_size, &max_size ) ; +#if defined(_MT) || defined(_REENTRANT) + //#ifdef _MT + printf("threads (min, max): ") ; + scanf("%d %d", &min_threads, &max_threads) ; + printf("chunks/thread: ") ; scanf("%d", &chperthread ) ; + printf("no of rounds: ") ; scanf("%d", &num_rounds ) ; + num_chunks = max_threads*chperthread ; +#else + printf("no of chunks: ") ; scanf("%d", &num_chunks ) ; +#endif + printf("random seed: ") ; scanf("%d", &seed) ; + + DoneWithInput: + + printf("Larson benchmark\n"); + if( num_chunks > MAX_BLOCKS ){ + printf("Max %d chunks - exiting\n", MAX_BLOCKS ) ; + return(1) ; + } + +#ifndef __WIN32__ +#ifdef __SVR4 + pthread_setconcurrency (max_threads); +#endif +#endif + printf("Initializing random number generator\n"); + + lran2_init(&rgen, seed) ; + // init_space = CountReservedSpace() ; + printf("Random generatior initialized\n"); + +#if defined(_MT) || defined(_REENTRANT) + //#ifdef _MT + runthreads(sleep_cnt, min_threads, max_threads, chperthread, num_rounds) ; +#else + runloops(sleep_cnt, num_chunks ) ; +#endif + +#ifdef _DEBUG + //_cputs("Hit any key to exit...") ; (void)_getch() ; +#endif + +#if 0 // defined(__SVR4) + { + psinfo_t ps; + int pid = getpid(); + char fname[255]; + sprintf (fname, "/proc/%d/psinfo", pid); + // sprintf (fname, "/proc/self/ps"); + FILE * f = fopen (fname, "rb"); + printf ("opening %s\n", fname); + if (f) { + fread (&ps, sizeof(ps), 1, f); + printf ("resident set size = %dK\n", ps.pr_rssize); + fclose (f); + } + } +#endif + + return(0) ; + +} /* main */ + +void runloops(long sleep_cnt, int num_chunks ) +{ + int cblks ; + int victim ; + size_t blk_size ; +#ifdef __WIN32__ + _LARGE_INTEGER ticks_per_sec, start_cnt, end_cnt; +#else + long ticks_per_sec ; + long start_cnt, end_cnt ; +#endif + _int64 ticks ; + double duration ; + double reqd_space ; + ULONG used_space=0 ; + long sum_allocs=0 ; + + QueryPerformanceFrequency( &ticks_per_sec ) ; + QueryPerformanceCounter( &start_cnt) ; + + for( cblks=0; cblks= sleep_cnt) break ; + } + reqd_space = (0.5*(min_size+max_size)*num_chunks) ; + // used_space = CountReservedSpace() - init_space; + + printf("%6.3f", duration ) ; + printf("%8.0f", sum_allocs/duration ) ; + printf(" %6.3f %.3f", (double)used_space/(1024*1024), used_space/reqd_space) ; + printf("\n") ; + +} + + +#if defined(_MT) || defined(_REENTRANT) +//#ifdef _MT +void runthreads(long sleep_cnt, int min_threads, int max_threads, int chperthread, int num_rounds) +{ + thread_data de_area[MAX_THREADS] ; + [[maybe_unused]] thread_data *pdea; + long nperthread ; + long sum_threads ; + _int64 sum_allocs ; + _int64 sum_frees ; + double duration ; +#ifdef __WIN32__ + _LARGE_INTEGER ticks_per_sec, start_cnt, end_cnt; +#else + long ticks_per_sec ; + long start_cnt, end_cnt ; +#endif + _int64 ticks ; + double rate_1=0, rate_n ; + [[maybe_unused]] double reqd_space ; + [[maybe_unused]] ULONG used_space ; + int prevthreads ; + int i ; + + QueryPerformanceFrequency( &ticks_per_sec ) ; + + pdea = &de_area[0] ; + memset(&de_area[0], 0, sizeof(thread_data)) ; + + printf("Running threads\n"); + prevthreads = 0; + for(num_threads=min_threads; num_threads <= max_threads; num_threads++ ) + { + + warmup(&blkp[prevthreads*chperthread], (num_threads-prevthreads)*chperthread ); + + //printf("Warmed up heap\n"); + nperthread = chperthread; + stopflag = FALSE ; + + for(i=0; i< num_threads; i++){ + de_area[i].threadno = i+1 ; + de_area[i].NumBlocks = num_rounds*nperthread; + de_area[i].array = &blkp[i*nperthread] ; + de_area[i].blksize = &blksize[i*nperthread] ; + de_area[i].asize = nperthread ; + de_area[i].min_size = min_size ; + de_area[i].max_size = max_size ; + de_area[i].seed = lran2(&rgen) ; ; + de_area[i].finished = 0 ; + de_area[i].cAllocs = 0 ; + de_area[i].cFrees = 0 ; + de_area[i].cThreads = 0 ; + de_area[i].finished = FALSE ; + lran2_init(&de_area[i].rgen, de_area[i].seed) ; + + #ifdef __WIN32__ + _beginthread((void (__cdecl*)(void *)) exercise_heap, 0, &de_area[i]) ; + #else + _beginthread(exercise_heap, 0, &de_area[i]) ; + #endif + + } + + QueryPerformanceCounter( &start_cnt) ; + + // printf ("Sleeping for %ld seconds.\n", sleep_cnt); + Sleep(sleep_cnt * 1000L) ; + + stopflag = TRUE ; + + for(i=0; ipd().avail_ram().value); + +#if 0 + printf("%2d ", num_threads ) ; + printf("%6.3f", duration ) ; + printf("%6.3f", rate_n/rate_1 ) ; + printf("%8.0f", sum_allocs/duration ) ; + printf(" %6.3f %.3f", (double)used_space/(1024*1024), used_space/reqd_space) ; + printf("\n") ; +#endif + + Sleep(2500L) ; // wait 5 sec for old threads to die + + prevthreads = num_threads ; + + //printf ("Done sleeping...\n"); + + } +} + + +static void * exercise_heap( void *pinput) +{ + thread_data *pdea; + int cblks=0 ; + int victim ; + size_t blk_size; + int range ; + + if( stopflag ) return 0; + + pdea = (thread_data *)pinput ; + pdea->finished = FALSE ; + pdea->cThreads++ ; + range = pdea->max_size - pdea->min_size ; + + [[maybe_unused]] Genode::Affinity::Location loc = Genode::Thread::myself()->affinity(); + [[maybe_unused]] Genode::Thread::Name name = Genode::Thread::myself()->name(); + + //printf("%s running at (%u,%u)\n", name.string(), loc.xpos(), loc.ypos()); + /* allocate NumBlocks chunks of random size */ + for( cblks=0; cblksNumBlocks; cblks++){ + victim = lran2(&pdea->rgen)%pdea->asize ; +#ifdef CPP +#if defined(SIZED) + operator delete[] (pdea->array[victim], pdea->blksize[victim]); +#else + delete[] pdea->array[victim] ; +#endif +#else + CUSTOM_FREE(pdea->array[victim]) ; +#endif + pdea->cFrees++ ; + + if (range == 0) { + blk_size = pdea->min_size; + } else { + blk_size = pdea->min_size+lran2(&pdea->rgen)%range ; + } +#ifdef CPP + pdea->array[victim] = new char[blk_size] ; +#else + pdea->array[victim] = (char *) CUSTOM_MALLOC(blk_size) ; +#endif + + pdea->blksize[victim] = blk_size ; + assert(pdea->array[victim] != NULL) ; + + pdea->cAllocs++ ; + + /* Write something! */ + + volatile char * chptr = ((char *) pdea->array[victim]); + *chptr++ = 'a'; + [[maybe_unused]] volatile char ch = *((char *) pdea->array[victim]); + *chptr = 'b'; + + + if( stopflag ) break ; + } + + // printf("Thread %u terminating: %d allocs, %d frees\n", + // pdea->threadno, pdea->cAllocs, pdea->cFrees) ; + pdea->finished = TRUE ; + + + if( !stopflag ){ +#ifdef __WIN32__ + _beginthread((void (__cdecl*)(void *)) exercise_heap, 0, pdea) ; +#else + //_beginthread(exercise_heap, 0, pdea) ; +#endif + } else { + //printf ("thread stopping.\n"); + } + + //end_thread(); + +#ifndef _WIN32 + pthread_exit (NULL); +#endif + return 0; +} + +static void warmup(char **blkp, int num_chunks ) +{ + int cblks ; + int victim ; + size_t blk_size ; + LPVOID tmp ; + size_t tmp_sz; + + + for( cblks=0; cblks 0 ; cblks--){ + victim = lran2(&rgen)%cblks ; + tmp = blkp[victim] ; + tmp_sz = blksize[victim]; + blkp[victim] = blkp[cblks-1] ; + blksize[victim] = blksize[cblks-1]; + blkp[cblks-1] = (char *) tmp ; + blksize[cblks-1] = tmp_sz; + } + + for( cblks=0; cblks<4*num_chunks; cblks++){ + victim = lran2(&rgen)%num_chunks ; +#ifdef CPP +#if defined(SIZED) + operator delete[] (blkp[victim], blksize[victim]); +#else + delete[] blkp[victim] ; +#endif +#else + CUSTOM_FREE(blkp[victim]) ; +#endif + + if (max_size == min_size) { + blk_size = min_size; + } else { + blk_size = min_size+lran2(&rgen)%(max_size - min_size) ; + } +#ifdef CPP + blkp[victim] = new char[blk_size] ; +#else + blkp[victim] = (char *) CUSTOM_MALLOC(blk_size) ; +#endif + blksize[victim] = blk_size ; + assert(blkp[victim] != NULL) ; + } +} +#endif // _MT + +#ifdef __WIN32__ +ULONG CountReservedSpace() +{ + MEMORY_BASIC_INFORMATION info; + char *addr=NULL ; + ULONG size=0 ; + + while( true){ + VirtualQuery(addr, &info, sizeof(info)); + switch( info.State){ + case MEM_FREE: + case MEM_RESERVE: + break ; + case MEM_COMMIT: + size += info.RegionSize ; + break ; + } + addr += info.RegionSize ; + if( addr >= (char *)0x80000000UL ) break ; + } + + return size ; + +} +#endif + +void Libc::Component::construct(Libc::Env &env) +{ + Genode::Attached_rom_dataspace _config{env, "config"}; + Genode::Xml_node config = _config.xml(); + + Genode::Heap heap{env.ram(), env.rm()}; + + _env = &env; + + Libc::with_libc([&]() + { _alloc = new (heap) Allocator(env.pd(), env.rm()); + int max_threads, min_threads; + int num_rounds; + int chperthread; + unsigned seed=12345; + long sleep_ent; + + sleep_ent = config.attribute_value("sleep_cnt", 10L); + min_size = config.attribute_value("min_size", 8); + max_size = config.attribute_value("max_size", 1000); + chperthread = config.attribute_value("chperthread", 5000); + num_rounds = config.attribute_value("rounds", 100); + seed = config.attribute_value("seed", 4141); + max_threads = config.attribute_value("max_threads", 32); + min_threads = config.attribute_value("min_threads", 1); + [[maybe_unused]] unsigned sbs = config.attribute_value("sbs_reserved", 4); + + char arg1[10]; + char arg2[10]; + char arg3[10]; + char arg4[10]; + char arg5[10]; + char arg6[10]; + char arg7[10]; + char arg8[10]; + + sprintf(arg1, "%ld", sleep_ent); + sprintf(arg2, "%d", min_size); + sprintf(arg3, "%d", max_size); + sprintf(arg4, "%d", chperthread); + sprintf(arg5, "%d", num_rounds); + sprintf(arg6, "%d", seed); + sprintf(arg7, "%d", max_threads); + sprintf(arg8, "%d", min_threads); + + char *argv[9] = {"larsonN", arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8}; + + /*for (size_t min = 64; min < 2048; min += 64) { + printf("Reserving %u superblocks for size class %lu", sbs, min); + _alloc->reserve_superblocks(sbs, min, 1); + }*/ + + main(9, argv); }); +} + +// ======================================================= + +/* lran2.h + * by Wolfram Gloger 1996. + * + * A small, portable pseudo-random number generator. + */ + +#ifndef _LRAN2_H +#define _LRAN2_H + +#define LRAN2_MAX 714025l /* constants for portable */ +#define IA 1366l /* random number generator */ +#define IC 150889l /* (see e.g. `Numerical Recipes') */ + +//struct lran2_st { +// long x, y, v[97]; +//}; + +static void +lran2_init(struct lran2_st* d, long seed) +{ + long x; + int j; + + x = (IC - seed) % LRAN2_MAX; + if(x < 0) x = -x; + for(j=0; j<97; j++) { + x = (IA*x + IC) % LRAN2_MAX; + d->v[j] = x; + } + d->x = (IA*x + IC) % LRAN2_MAX; + d->y = d->x; +} + +static +long lran2(struct lran2_st* d) +{ + int j = (d->y % 97); + + d->y = d->v[j]; + d->x = (IA*d->x + IC) % LRAN2_MAX; + d->v[j] = d->x; + return d->y; +} + +#undef IA +#undef IC + +#endif diff --git a/repos/ealanos/src/bench/larson/target.mk b/repos/ealanos/src/bench/larson/target.mk new file mode 100644 index 0000000000..49af60f533 --- /dev/null +++ b/repos/ealanos/src/bench/larson/target.mk @@ -0,0 +1,4 @@ +TARGET = larson +SRC_CC = larson.cpp +LIBS += base libm libc stdcxx +CC_OPT += -Wno-error -Wno-permissive -fpermissive -DPRIVATE -Wno-error=conversion -Wno-error=write-strings \ No newline at end of file