diff --git a/README-alpha b/README-alpha index 9f6fdff..1fe2c91 100644 --- a/README-alpha +++ b/README-alpha @@ -16,7 +16,7 @@ installation instructions are set forth in the file README. incomplete. The subversion history is the authoritative documentation of all recent changes. -Report bugs at https://labs.omniti.com/trac/portableumem/newticket +Report bugs at https://github.com/gburd/libumem/issues * Checking Out the Sources @@ -31,20 +31,30 @@ To checkout the source tree from subversion issue the following command: In order to build this you will first need to have right versions of autotools and some auxiliary GNU programs. At the time of this -writing these are: +writing these are: Package Version (>=) ======== ============ automake 1.4 autoconf 2.50 libtool 1.5.0 - + To prepare the package for building run autogen.sh. Then run ./configure with the desired options (See INSTALL and README for the detailed instructions). Finally, run make. Notice that the first make of the package should be made in the source directory. Subsequent makes can use build directory different from the source one. +* Use + + To use link with both umem and umem_malloc (e.g. '-lumem -lumem_malloc'). + +* Testing + + There are two basic test files included, test.c and hello.c, with +basic instructions within those files at the end. Basic performance +testing was done using hyperfine. + * Copyright information: Please see COPYRIGHT and OPENSOLARIS.LICENSE for the copyright diff --git a/hello.c b/hello.c new file mode 100644 index 0000000..69055e7 --- /dev/null +++ b/hello.c @@ -0,0 +1,17 @@ +#include +#include + +int main() { + char *ptr = (char *)malloc(4096); + snprintf(ptr, 4096, "%s", "Hello, World!"); + printf("%s 0x%p\n", ptr, ptr); + return 0; +} + +/* + * Local variables: + * tab-width:4 + * compile-command: "gcc -fpic -Wall -Werror -Ofast -march=native -mtune=native hello.c -o hello" + * End: + */ + diff --git a/test.c b/test.c new file mode 100644 index 0000000..612e7de --- /dev/null +++ b/test.c @@ -0,0 +1,521 @@ +/* malloc-test.c + * by Wolfram Gloger 1995, 1996 + * + * This program is provided `as is', there is no warranty. + * https://raw.githubusercontent.com/emeryberger/Malloc-Implementations/master/allocators/CAMA/malloc-test.c + */ + +#if !defined(__STDC__) +#define __STDC__ 1 +#endif + +#include +#include + +#if !defined(_WIN32) +#include +#include +#include +#include +#endif + +#ifndef MEMORY +#define MEMORY 4000000l +#endif +#ifndef BINS_MAX +#define BINS_MAX 32768 +#endif +#define SBINS_MAX 1024 +#define SIZE 4024 +#define I_MAX 5000 +#ifndef I_AVERAGE +#define I_AVERAGE 200 +#endif +#define ACTIONS_MAX 50 +#ifndef SBRK_AVG +#define SBRK_AVG 0 +#endif +#ifndef MMAP_THRESH +#define MMAP_THRESH 0 +#endif +#ifndef TEST +#define TEST 4 /* minimal testing */ +#endif +#ifndef TEST_INC +#define TEST_INC 2047 +#endif +#if defined(__i386__) || defined(__sparc__) || defined(mips) || defined(_WIN32) +#define PAGE_SIZE 4096 +#elif defined(__alpha__) +#define PAGE_SIZE 8192 +#elif defined(__SVR4) +#define PAGE_SIZE 8192 +#else +#define PAGE_SIZE 4096 /* default */ +#endif +#define RANDOM(s) (lran2(0) % (s)) + +/* All probabilities are parts in 1024. */ +#ifndef PROB_MEMALIGN +#define PROB_MEMALIGN 0 +#endif +#ifndef PROB_REALLOC +#define PROB_REALLOC 48 +#endif +#ifndef PROB_CALLOC +#define PROB_CALLOC 0 +#endif + +struct bin { + unsigned char *ptr; + unsigned long size; +} m[BINS_MAX], sm[SBINS_MAX]; + +unsigned long size = SIZE, bins=0, sbins=0; +unsigned long total_size=0, total_size_max=0; +unsigned char *base_ptr; +unsigned long base_save; + +long +#if __STDC__ +lran2(long seed) +#else + lran2(seed) long seed; +#endif +#define LRAN2_MAX 714025l /* constants for portable */ +#define IA 1366l /* random number generator */ +#define IC 150889l /* (see Numerical Recipes p. 211) */ +{ + static int first = 1; + static long x, y, v[97]; + int j; + + if(seed || first) { + first = 0; + x = (IC - seed) % LRAN2_MAX; + if(x < 0) x = -x; + for(j=0; j<97; j++) { + x = (IA*x + IC) % LRAN2_MAX; + v[j] = x; + } + x = (IA*x + IC) % LRAN2_MAX; + y = x; + } + j = y % 97; + y = v[j]; + x = (IA*x + IC) % LRAN2_MAX; + v[j] = x; + return y; +} +#undef IA +#undef IC + +void +#if __STDC__ +mem_init(unsigned char *ptr, unsigned long size) +#else + mem_init(ptr, size) unsigned char *ptr; unsigned long size; +#endif +{ + unsigned long i, j; + + if(size == 0) return; + if(size > sizeof(unsigned long)) { + /* Try the complete initial word. */ + *(unsigned long *)ptr = (unsigned long)ptr ^ size; + i = TEST_INC; + } else + i = 0; + for(; i>8)) & 0xFF); + } + j = (unsigned long)ptr ^ (size-1); + ptr[size-1] = ((j ^ (j>>8)) & 0xFF); +} + +int +#if __STDC__ +mem_check(unsigned char *ptr, unsigned long size) +#else + mem_check(ptr, size) unsigned char *ptr; unsigned long size; +#endif +{ + unsigned long i, j; + + if(size == 0) return 0; + if(size > sizeof(unsigned long)) { + if(*(unsigned long *)ptr != ((unsigned long)ptr ^ size)) { + printf ("failed size check: expected %lx, found %lx!\n", + ((unsigned long) ptr ^ size), *(unsigned long *) ptr); + return 1; + } + i = TEST_INC; + } else + i = 0; + for(; i>8)) & 0xFF)) return 2; + } + j = (unsigned long)ptr ^ (size-1); + if(ptr[size-1] != ((j ^ (j>>8)) & 0xFF)) { + printf ("failed last byte check: expected %lx, found %x!\n", + ((unsigned long) ((j ^ (j>>8)) & 0xFF)), ptr[size-1]); + return 3; + } + return 0; +} + +long +#if __STDC__ +random_size(long max) +#else + random_size(max) long max; +#endif +{ + long r1, r2, r, max_pages; + + max_pages = max/PAGE_SIZE; + if(max_pages > 0) { + r1 = RANDOM(1024); + r2 = (r1 & 7)*4; + if(r1 < 512) { + /* small value near power of two */ + r = (1L << (r1 >> 6)) + r2; + } else if(r1 < 512+20) { + /* value near a multiple of the page size */ + r = (RANDOM(max_pages)+1)*PAGE_SIZE + r2 - 16; + /*printf("r = %4lx\n", r);*/ + } else r = RANDOM(max) + 1; + } else r = RANDOM(max) + 1; + /*if(r <= 0) exit(-1);*/ + return r; +} + +void +#if __STDC__ +bin_alloc(struct bin *m) +#else + bin_alloc(m) struct bin *m; +#endif +{ + long r, key; + unsigned long sz; + +#if TEST > 0 + if(mem_check(m->ptr, m->size)) { + printf("bin_alloc: memory corrupt at %p, size=%lu!\n", m->ptr, m->size); + exit(1); + } +#endif + total_size -= m->size; + r = RANDOM(1024); + if(r < PROB_MEMALIGN) { +#if !defined(_WIN32) + if(m->size > 0) free(m->ptr); + m->size = random_size(size); +#if PROB_MEMALIGN + m->ptr = (unsigned char *)memalign(4 << RANDOM(8), m->size); +#endif + +#endif + } else if(r < (PROB_MEMALIGN + PROB_REALLOC)) { + if(m->size == 0) { +#ifndef __sparc__ + m->ptr = NULL; +#else + /* SunOS4 does not realloc() a NULL pointer */ + m->ptr = (unsigned char *)malloc(1); +#endif + } +#if TEST > 2 + key = RANDOM(256); + sz = m->size; + for(r=0; rptr[r] = (r ^ key) & 0xFF; +#endif + m->size = random_size(size); + /*printf("realloc %d\n", (int)m->size);*/ + m->ptr = (unsigned char *)realloc(m->ptr, m->size); +#if TEST > 2 + if(m->size < sz) sz = m->size; + for(r=0; rptr[r] != ((r ^ key) & 0xFF)) { + printf("realloc bug !\n"); + exit(1); + } +#endif + } else if(r < (PROB_MEMALIGN + PROB_REALLOC + PROB_CALLOC)) { + if(m->size > 0) free(m->ptr); + m->size = random_size(size); + m->ptr = (unsigned char *)calloc(m->size, 1); +#if TEST > 2 + for(r=0; rsize; r++) + if(m->ptr[r] != '\0') { + printf("calloc bug !\n"); + exit(1); + } +#endif + } else { /* normal malloc call */ + if(m->size > 0) free(m->ptr); + m->size = random_size(size); + m->ptr = (unsigned char *)malloc(m->size); + } + if(!m->ptr) { + printf("out of memory!\n"); + exit(1); + } + total_size += m->size; + if(total_size > total_size_max) total_size_max = total_size; +#if TEST > 0 + mem_init(m->ptr, m->size); +#endif + if(m->ptr < base_ptr) { +#ifdef VERBOSE + printf("hmmm, allocating below brk...\n"); +#endif + base_ptr = m->ptr; + } +} + +void +#if __STDC__ +bin_free(struct bin *m) +#else + bin_free(m) struct bin *m; +#endif +{ + if(m->size == 0) return; +#if TEST > 0 + if(mem_check(m->ptr, m->size)) { + printf("bin_free: memory corrupt!\n"); + exit(1); + } +#endif + total_size -= m->size; + free(m->ptr); + m->size = 0; +} + +void +bin_test() +{ + unsigned int b; + int v; + // printf ("bin_test.\n"); + + for(b=0; b= 1000000) { + total_usec -= 1000000; + total_sec++; + } + printf(" t=%ld.%06ldsec", total_sec, total_usec); +#endif +} + +int +#if __STDC__ +main(int argc, char *argv[]) +#else + main(argc, argv) int argc; char *argv[]; +#endif +{ + int i, j, next_i, count, max=I_MAX, actions; + unsigned int b; + long sbrk_max, sum; + double sbrk_used_sum, total_size_sum; + + if(argc > 1) max = atoi(argv[1]); + if(argc > 2) size = atoi(argv[2]); + lran2((long)max ^ size); + bins = (MEMORY/size)*4; + if(bins > BINS_MAX) bins = BINS_MAX; +#if 0 // FIX ME? Disable sbrk... + base_ptr = (unsigned char *)sbrk(0); + sum = (long)base_ptr % PAGE_SIZE; + if(sum > 0) { + if((char *)sbrk((long)PAGE_SIZE - sum) == (char *)-1) exit(1); + base_ptr += (long)PAGE_SIZE - sum; + /*printf("base_ptr = %lx\n", (long)base_ptr);*/ + } + /* attempt to fill up the region below the initial brk */ + void* dummy = 0; + for(i=0; i<10000; i++) { + dummy = malloc(1); + if(dummy >= (void*)base_ptr) break; + } + free(dummy); + base_save = ((unsigned long)base_ptr >> 24) << 24; +#endif + +#if MMAP_THRESH > 0 + if(!mallopt(-3, MMAP_THRESH)) printf("mallopt failed!\n"); + if(!mallopt(-4, 200)) printf("mallopt failed!\n"); +#endif +#ifdef VERBOSE + printf("# mmap_thresh=%d\n", MMAP_THRESH); + printf("# bins=%d max=%d size=%d\n", bins, max, size); + printf("# base=%lx\n", base_save); +#endif + for(b=0; b 1 + bin_test(); +#endif +#ifdef MSTATS + malloc_stats(); +#endif + actions = RANDOM(ACTIONS_MAX); + for(j=0; j 3 + bin_test(); +#endif + } + i += actions; +#ifdef AFTER_FREE + AFTER_FREE; +#endif +#if SBRK_AVG > 0 + if(sbins0 && sm[sbins].ptr==(sm[sbins-1].ptr+sm[sbins-1].size)) { + sm[sbins-1].size += sm[sbins].size; + sbins--; + } +#ifdef VERBOSE + printf("sbrk #%d %p %ld\n", sbins, sm[sbins].ptr, sm[sbins].size); +#endif +#if TEST > 0 + mem_init(sm[sbins].ptr, sm[sbins].size); +#endif + sbins++; + } +#endif + actions = RANDOM(ACTIONS_MAX); + for(j=0; j 3 + bin_test(); +#endif + } + i += actions; + if(i >= next_i) { /* gather statistics */ + count++; +#if !defined(_WIN32) + sum = (long)sbrk(0); +#else + sum = 0; +#endif + if(sum > sbrk_max) sbrk_max = sum; + sbrk_used_sum += sum; + total_size_sum += (double)total_size; +#ifdef VERBOSE + printf("%8d %7lu\n", i, total_size); +#endif + next_i += I_AVERAGE; + } + } + + /* Correct sbrk values. */ + sbrk_max -= (long)base_ptr; + sbrk_used_sum -= (double)count*(long)base_ptr; +#ifdef VERBOSE + printf("# initial brk: %lx\n", (long)base_ptr); + printf("# max. sbrk()'ed memory: %ld bytes\n", sbrk_max); + printf("# avg. sbrk()'ed memory: %ld bytes\n", + (long)(sbrk_used_sum/count)); + printf("# current size allocated: %ld bytes\n", total_size); + printf("# maximum size allocated: %ld bytes\n", total_size_max); + printf("# average size allocated: %.1f bytes\n", total_size_sum/count); + printf("# current heap waste: %.2f%%\n", + (1.0 - (double)total_size_max/sbrk_max)*100.0); + printf("# average heap waste: %.2f%%\n", + (1.0 - (double)total_size_sum/sbrk_used_sum)*100.0); + printf("# total sbrk calls performed: %d\n", sbins); +#else + printf("size=%7ld waste=%7.3f%%", size, + /* (1.0 - (double)total_size_max/sbrk_max)*100.0, */ + (1.0 - (double)total_size_sum/sbrk_used_sum)*100.0); + print_times(); + printf("\n"); +#endif + return 0; +} + +/* testing: + * gcc -Wall -Werror -fpic -march=native -mtune=native -Ofast test.c -o test + * gcc -Wall -Werror -fpic -march=native -mtune=native -Ofast test.c -o test -lumem -lumem_malloc + * + * https://github.com/sharkdp/hyperfine + * + + $ ldd test + linux-vdso.so.1 (0x00007ffc607de000) + libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb619a4d000) + /lib64/ld-linux-x86-64.so.2 (0x00007fb619ce9000) +$ ldd test_umem + linux-vdso.so.1 (0x00007ffd1ff59000) + libumem_malloc.so.0 => /usr/local/lib/libumem_malloc.so.0 (0x00007fe885b18000) + libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe885926000) + libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fe885903000) + libumem.so.0 => /usr/local/lib/libumem.so.0 (0x00007fe88585b000) + /lib64/ld-linux-x86-64.so.2 (0x00007fe885bc7000) + libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fe885855000) + +$ hyperfine --warmup 3 --min-runs 10 ./test +Benchmark #1: ./test + Time (mean ± σ): 82.1 ms ± 1.1 ms [User: 81.0 ms, System: 0.9 ms] + Range (min … max): 79.3 ms … 84.4 ms 35 runs + +$ hyperfine --warmup 3 --min-runs 10 ./test_umem +Benchmark #1: ./test_umem + Time (mean ± σ): 85.7 ms ± 1.5 ms [User: 83.2 ms, System: 2.5 ms] + Range (min … max): 81.8 ms … 89.2 ms 34 runs + + */ + +/* + * Local variables: + * tab-width:4 + * compile-command: "gcc -fpic -Wall -Werror -Ofast -march=native -mtune=native test.c -o test" + * End: + */