Added all contents of liballoc

master Current
Bryce Lanham 11 years ago
commit 78f44b72d5

26
HOWTO

@ -0,0 +1,26 @@
This is a step-by-step instruction guide detailing how to
implement the library on your own system.
1. Copy the "liballoc.c" and "liballoc.h" files into
your working directory. (Whatever project you want
to use it in).
2. Create the hooks that the library needs:
Make a new file called "liballoc_hooks.c" (or
whatever) and implement the functions detailed
in the README and explained in "liballoc.h"
Look at "linux.c" for an example. It implements
the hooks for a Linux system.
3. Be sure to include the "liballoc.h" header
into your C/C++ files that are using the
malloc/free/memory operations. (So that
malloc/free/etc are declared.. obviously.)
4. Compile as per your normal method and test.

@ -0,0 +1,10 @@
This code is released into the public domain. Use this code at your own
risk. Feel free to use it for whatever purpose you want. I take no responsibilty or
whatever if anything goes wrong. Use it at your own risk.
If you have any fixes or patches, please email me.
Durand Miller <clutter@djm.co.za>

@ -0,0 +1,54 @@
# Please see LICENSE for licensing information.
# --------- FLAGS AND VARIABLES --------------------
CFLAGS=-O2 -nostdlib -nodefaultlibs -fno-builtin -fPIC -Wall
HEADERPATH=-I./
# --------- GENERIC MAKE RULES --------------------
all:
@echo "Makefile for the liballoc library."
@echo "Please see LICENSE for licensing information."
@echo
@echo "Output should be: liballoc.a "
@echo " liballoc.so"
@echo
@echo "Usage: make [ compile | clean | <platform> ] "
@echo
@echo "Currently supported platforms:"
@echo
@echo " linux"
@echo " linux_debug"
@echo
@echo
@echo "Please see the README for example usage"
clean:
rm -f ./*.o
rm -f ./*.a
rm -f ./*.so
compile:
gcc $(HEADERPATH) $(CFLAGS) -static -c liballoc.c
ar -rcv liballoc.a *.o
gcc $(HEADERPATH) $(CFLAGS) -shared liballoc.c -o liballoc.so
linux:
gcc $(HEADERPATH) $(CFLAGS) -static -c liballoc.c linux.c
ar -rcv liballoc.a *.o
gcc $(HEADERPATH) $(CFLAGS) -shared liballoc.c linux.c -o liballoc.so
linux_debug:
gcc -DDEBUG $(HEADERPATH) $(CFLAGS) -static -c liballoc.c linux.c
ar -rcv liballoc.a *.o
gcc -DDEBUG $(HEADERPATH) $(CFLAGS) -shared liballoc.c linux.c -o liballoc.so

@ -0,0 +1,58 @@
There are 4 functions which you need to implement on your system:
int liballoc_lock();
int liballoc_unlock();
void* liballoc_alloc(int);
int liballoc_free(void*,int);
1) Have a look at liballoc.h for information about what each function is
supposed to do.
2) Have a look at linux.c for an example of how to implement the library
on linux.
NOTE: There are two ways to build the library.
1) Compile the library with a new system file. For example, I've
left linux.c with the default distribution. It gets compiled
directly into the liballoc_linux.so file.
2) Implement the functions in your application and then just
link against the default liballoc.so library when you compile
your app.
QUICK START
-------------
You can simply type: "make linux" to build the linux shared
library. Thereafter, you can link it directly into your applications
during build or afterwards by export the LD_PRELOAD environment
variable.
To run bash with the library, for example:
LD_PRELOAD=/full/path/to/liballoc.so bash
The above command will pre-link the library into the application,
essentially replacing the default malloc/free calls at runtime. It's
quite cool.
Durand Miller
clutter@djm.co.za

@ -0,0 +1,534 @@
#include <liballoc.h>
/** Durand's Ridiculously Amazing Super Duper Memory functions. */
//#define DEBUG
#define LIBALLOC_MAGIC 0xc001c0de
#define MAXCOMPLETE 5
#define MAXEXP 32
#define MINEXP 8
#define MODE_BEST 0
#define MODE_INSTANT 1
#define MODE MODE_BEST
#ifdef DEBUG
#include <stdio.h>
#endif
struct boundary_tag* l_freePages[MAXEXP]; //< Allowing for 2^MAXEXP blocks
int l_completePages[MAXEXP]; //< Allowing for 2^MAXEXP blocks
#ifdef DEBUG
unsigned int l_allocated = 0; //< The real amount of memory allocated.
unsigned int l_inuse = 0; //< The amount of memory in use (malloc'ed).
#endif
static int l_initialized = 0; //< Flag to indicate initialization.
static int l_pageSize = 4096; //< Individual page size
static int l_pageCount = 16; //< Minimum number of pages to allocate.
// *********** HELPER FUNCTIONS *******************************
/** Returns the exponent required to manage 'size' amount of memory.
*
* Returns n where 2^n <= size < 2^(n+1)
*/
static inline int getexp( unsigned int size )
{
if ( size < (1<<MINEXP) )
{
#ifdef DEBUG
printf("getexp returns -1 for %i less than MINEXP\n", size );
#endif
return -1; // Smaller than the quantum.
}
int shift = MINEXP;
while ( shift < MAXEXP )
{
if ( (1<<shift) > size ) break;
shift += 1;
}
#ifdef DEBUG
printf("getexp returns %i (%i bytes) for %i size\n", shift - 1, (1<<(shift -1)), size );
#endif
return shift - 1;
}
static void* liballoc_memset(void* s, int c, size_t n)
{
int i;
for ( i = 0; i < n ; i++)
((char*)s)[i] = c;
return s;
}
static void* liballoc_memcpy(void* s1, const void* s2, size_t n)
{
char *cdest;
char *csrc;
unsigned int *ldest = (unsigned int*)s1;
unsigned int *lsrc = (unsigned int*)s2;
while ( n >= sizeof(unsigned int) )
{
*ldest++ = *lsrc++;
n -= sizeof(unsigned int);
}
cdest = (char*)ldest;
csrc = (char*)lsrc;
while ( n > 0 )
{
*cdest++ = *csrc++;
n -= 1;
}
return s1;
}
#ifdef DEBUG
static void dump_array()
{
int i = 0;
struct boundary_tag *tag = NULL;
printf("------ Free pages array ---------\n");
printf("System memory allocated: %i\n", l_allocated );
printf("Memory in used (malloc'ed): %i\n", l_inuse );
for ( i = 0; i < MAXEXP; i++ )
{
printf("%.2i(%i): ",i, l_completePages[i] );
tag = l_freePages[ i ];
while ( tag != NULL )
{
if ( tag->split_left != NULL ) printf("*");
printf("%i", tag->real_size );
if ( tag->split_right != NULL ) printf("*");
printf(" ");
tag = tag->next;
}
printf("\n");
}
printf("'*' denotes a split to the left/right of a tag\n");
fflush( stdout );
}
#endif
static inline void insert_tag( struct boundary_tag *tag, int index )
{
int realIndex;
if ( index < 0 )
{
realIndex = getexp( tag->real_size - sizeof(struct boundary_tag) );
if ( realIndex < MINEXP ) realIndex = MINEXP;
}
else
realIndex = index;
tag->index = realIndex;
if ( l_freePages[ realIndex ] != NULL )
{
l_freePages[ realIndex ]->prev = tag;
tag->next = l_freePages[ realIndex ];
}
l_freePages[ realIndex ] = tag;
}
static inline void remove_tag( struct boundary_tag *tag )
{
if ( l_freePages[ tag->index ] == tag ) l_freePages[ tag->index ] = tag->next;
if ( tag->prev != NULL ) tag->prev->next = tag->next;
if ( tag->next != NULL ) tag->next->prev = tag->prev;
tag->next = NULL;
tag->prev = NULL;
tag->index = -1;
}
static inline struct boundary_tag* melt_left( struct boundary_tag *tag )
{
struct boundary_tag *left = tag->split_left;
left->real_size += tag->real_size;
left->split_right = tag->split_right;
if ( tag->split_right != NULL ) tag->split_right->split_left = left;
return left;
}
static inline struct boundary_tag* absorb_right( struct boundary_tag *tag )
{
struct boundary_tag *right = tag->split_right;
remove_tag( right ); // Remove right from free pages.
tag->real_size += right->real_size;
tag->split_right = right->split_right;
if ( right->split_right != NULL )
right->split_right->split_left = tag;
return tag;
}
static inline struct boundary_tag* split_tag( struct boundary_tag* tag )
{
unsigned int remainder = tag->real_size - sizeof(struct boundary_tag) - tag->size;
struct boundary_tag *new_tag =
(struct boundary_tag*)((unsigned int)tag + sizeof(struct boundary_tag) + tag->size);
new_tag->magic = LIBALLOC_MAGIC;
new_tag->real_size = remainder;
new_tag->next = NULL;
new_tag->prev = NULL;
new_tag->split_left = tag;
new_tag->split_right = tag->split_right;
if (new_tag->split_right != NULL) new_tag->split_right->split_left = new_tag;
tag->split_right = new_tag;
tag->real_size -= new_tag->real_size;
insert_tag( new_tag, -1 );
return new_tag;
}
// ***************************************************************
static struct boundary_tag* allocate_new_tag( unsigned int size )
{
unsigned int pages;
unsigned int usage;
struct boundary_tag *tag;
// This is how much space is required.
usage = size + sizeof(struct boundary_tag);
// Perfect amount of space
pages = usage / l_pageSize;
if ( (usage % l_pageSize) != 0 ) pages += 1;
// Make sure it's >= the minimum size.
if ( pages < l_pageCount ) pages = l_pageCount;
tag = (struct boundary_tag*)liballoc_alloc( pages );
if ( tag == NULL ) return NULL; // uh oh, we ran out of memory.
tag->magic = LIBALLOC_MAGIC;
tag->size = size;
tag->real_size = pages * l_pageSize;
tag->index = -1;
tag->next = NULL;
tag->prev = NULL;
tag->split_left = NULL;
tag->split_right = NULL;
#ifdef DEBUG
printf("Resource allocated %x of %i pages (%i bytes) for %i size.\n", tag, pages, pages * l_pageSize, size );
l_allocated += pages * l_pageSize;
printf("Total memory usage = %i KB\n", (int)((l_allocated / (1024))) );
#endif
return tag;
}
void *malloc(size_t size)
{
int index;
void *ptr;
struct boundary_tag *tag = NULL;
liballoc_lock();
if ( l_initialized == 0 )
{
#ifdef DEBUG
printf("%s\n","liballoc initializing.");
#endif
for ( index = 0; index < MAXEXP; index++ )
{
l_freePages[index] = NULL;
l_completePages[index] = 0;
}
l_initialized = 1;
}
index = getexp( size ) + MODE;
if ( index < MINEXP ) index = MINEXP;
// Find one big enough.
tag = l_freePages[ index ]; // Start at the front of the list.
while ( tag != NULL )
{
// If there's enough space in this tag.
if ( (tag->real_size - sizeof(struct boundary_tag))
>= (size + sizeof(struct boundary_tag) ) )
{
#ifdef DEBUG
printf("Tag search found %i >= %i\n",(tag->real_size - sizeof(struct boundary_tag)), (size + sizeof(struct boundary_tag) ) );
#endif
break;
}
tag = tag->next;
}
// No page found. Make one.
if ( tag == NULL )
{
if ( (tag = allocate_new_tag( size )) == NULL )
{
liballoc_unlock();
return NULL;
}
index = getexp( tag->real_size - sizeof(struct boundary_tag) );
}
else
{
remove_tag( tag );
if ( (tag->split_left == NULL) && (tag->split_right == NULL) )
l_completePages[ index ] -= 1;
}
// We have a free page. Remove it from the free pages list.
tag->size = size;
// Removed... see if we can re-use the excess space.
#ifdef DEBUG
printf("Found tag with %i bytes available (requested %i bytes, leaving %i), which has exponent: %i (%i bytes)\n", tag->real_size - sizeof(struct boundary_tag), size, tag->real_size - size - sizeof(struct boundary_tag), index, 1<<index );
#endif
unsigned int remainder = tag->real_size - size - sizeof( struct boundary_tag ) * 2; // Support a new tag + remainder
if ( ((int)(remainder) > 0) /*&& ( (tag->real_size - remainder) >= (1<<MINEXP))*/ )
{
int childIndex = getexp( remainder );
if ( childIndex >= 0 )
{
#ifdef DEBUG
printf("Seems to be splittable: %i >= 2^%i .. %i\n", remainder, childIndex, (1<<childIndex) );
#endif
struct boundary_tag *new_tag = split_tag( tag );
new_tag = new_tag; // Get around the compiler warning about unused variables.
#ifdef DEBUG
printf("Old tag has become %i bytes, new tag is now %i bytes (%i exp)\n", tag->real_size, new_tag->real_size, new_tag->index );
#endif
}
}
ptr = (void*)((unsigned int)tag + sizeof( struct boundary_tag ) );
#ifdef DEBUG
l_inuse += size;
printf("malloc: %x, %i, %i\n", ptr, (int)l_inuse / 1024, (int)l_allocated / 1024 );
dump_array();
#endif
liballoc_unlock();
return ptr;
}
void free(void *ptr)
{
int index;
struct boundary_tag *tag;
if ( ptr == NULL ) return;
liballoc_lock();
tag = (struct boundary_tag*)((unsigned int)ptr - sizeof( struct boundary_tag ));
if ( tag->magic != LIBALLOC_MAGIC )
{
liballoc_unlock(); // release the lock
return;
}
#ifdef DEBUG
l_inuse -= tag->size;
printf("free: %x, %i, %i\n", ptr, (int)l_inuse / 1024, (int)l_allocated / 1024 );
#endif
// MELT LEFT...
while ( (tag->split_left != NULL) && (tag->split_left->index >= 0) )
{
#ifdef DEBUG
printf("Melting tag left into available memory. Left was %i, becomes %i (%i)\n", tag->split_left->real_size, tag->split_left->real_size + tag->real_size, tag->split_left->real_size );
#endif
tag = melt_left( tag );
remove_tag( tag );
}
// MELT RIGHT...
while ( (tag->split_right != NULL) && (tag->split_right->index >= 0) )
{
#ifdef DEBUG
printf("Melting tag right into available memory. This was was %i, becomes %i (%i)\n", tag->real_size, tag->split_right->real_size + tag->real_size, tag->split_right->real_size );
#endif
tag = absorb_right( tag );
}
// Where is it going back to?
index = getexp( tag->real_size - sizeof(struct boundary_tag) );
if ( index < MINEXP ) index = MINEXP;
// A whole, empty block?
if ( (tag->split_left == NULL) && (tag->split_right == NULL) )
{
if ( l_completePages[ index ] == MAXCOMPLETE )
{
// Too many standing by to keep. Free this one.
unsigned int pages = tag->real_size / l_pageSize;
if ( (tag->real_size % l_pageSize) != 0 ) pages += 1;
if ( pages < l_pageCount ) pages = l_pageCount;
liballoc_free( tag, pages );
#ifdef DEBUG
l_allocated -= pages * l_pageSize;
printf("Resource freeing %x of %i pages\n", tag, pages );
dump_array();
#endif
liballoc_unlock();
return;
}
l_completePages[ index ] += 1; // Increase the count of complete pages.
}
// ..........
insert_tag( tag, index );
#ifdef DEBUG
printf("Returning tag with %i bytes (requested %i bytes), which has exponent: %i\n", tag->real_size, tag->size, index );
dump_array();
#endif
liballoc_unlock();
}
void* calloc(size_t nobj, size_t size)
{
int real_size;
void *p;
real_size = nobj * size;
p = malloc( real_size );
liballoc_memset( p, 0, real_size );
return p;
}
void* realloc(void *p, size_t size)
{
void *ptr;
struct boundary_tag *tag;
int real_size;
if ( size == 0 )
{
free( p );
return NULL;
}
if ( p == NULL ) return malloc( size );
if ( liballoc_lock != NULL ) liballoc_lock(); // lockit
tag = (struct boundary_tag*)((unsigned int)p - sizeof( struct boundary_tag ));
real_size = tag->size;
if ( liballoc_unlock != NULL ) liballoc_unlock();
if ( real_size > size ) real_size = size;
ptr = malloc( size );
liballoc_memcpy( ptr, p, real_size );
free( p );
return ptr;
}

@ -0,0 +1,99 @@
#ifndef _LIBALLOC_H
#define _LIBALLOC_H
// If we are told to not define our own size_t, then we
// skip the define.
#ifndef _ALLOC_SKIP_DEFINE
#ifndef _HAVE_SIZE_T
#define _HAVE_SIZE_T
typedef unsigned int size_t;
#endif
#ifndef NULL
#define NULL 0
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
/** This is a boundary tag which is prepended to the
* page or section of a page which we have allocated. It is
* used to identify valid memory blocks that the
* application is trying to free.
*/
struct boundary_tag
{
unsigned int magic; //< It's a kind of ...
unsigned int size; //< Requested size.
unsigned int real_size; //< Actual size.
int index; //< Location in the page table.
struct boundary_tag *split_left; //< Linked-list info for broken pages.
struct boundary_tag *split_right; //< The same.
struct boundary_tag *next; //< Linked list info.
struct boundary_tag *prev; //< Linked list info.
};
/** This function is supposed to lock the memory data structures. It
* could be as simple as disabling interrupts or acquiring a spinlock.
* It's up to you to decide.
*
* \return 0 if the lock was acquired successfully. Anything else is
* failure.
*/
extern int liballoc_lock();
/** This function unlocks what was previously locked by the liballoc_lock
* function. If it disabled interrupts, it enables interrupts. If it
* had acquiried a spinlock, it releases the spinlock. etc.
*
* \return 0 if the lock was successfully released.
*/
extern int liballoc_unlock();
/** This is the hook into the local system which allocates pages. It
* accepts an integer parameter which is the number of pages
* required. The page size was set up in the liballoc_init function.
*
* \return NULL if the pages were not allocated.
* \return A pointer to the allocated memory.
*/
extern void* liballoc_alloc(int);
/** This frees previously allocated memory. The void* parameter passed
* to the function is the exact same value returned from a previous
* liballoc_alloc call.
*
* The integer value is the number of pages to free.
*
* \return 0 if the memory was successfully freed.
*/
extern int liballoc_free(void*,int);
void *malloc(size_t); //< The standard function.
void *realloc(void *, size_t); //< The standard function.
void *calloc(size_t, size_t); //< The standard function.
void free(void *); //< The standard function.
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,64 @@
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/mman.h>
#include <unistd.h>
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
# define MAP_ANONYMOUS MAP_ANON
#endif
#if !defined(MAP_FAILED)
# define MAP_FAILED ((char*)-1)
#endif
#ifndef MAP_NORESERVE
# ifdef MAP_AUTORESRV
# define MAP_NORESERVE MAP_AUTORESRV
# else
# define MAP_NORESERVE 0
# endif
#endif
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static int page_size = -1;
int liballoc_lock()
{
pthread_mutex_lock( &mutex );
return 0;
}
int liballoc_unlock()
{
pthread_mutex_unlock( &mutex );
return 0;
}
void* liballoc_alloc( int pages )
{
if ( page_size < 0 ) page_size = getpagesize();
unsigned int size = pages * page_size;
char *p2 = (char*)mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_NORESERVE|MAP_ANONYMOUS, -1, 0);
if ( p2 == MAP_FAILED) return NULL;
if(mprotect(p2, size, PROT_READ|PROT_WRITE) != 0)
{
munmap(p2, size);
return NULL;
}
return p2;
}
int liballoc_free( void* ptr, int pages )
{
return munmap( ptr, pages * page_size );
}

@ -0,0 +1,22 @@
FILES=main.cpp malloc_test.cpp
all:
@echo "Hello! This is an arbitrary test."
@echo
@echo "Usage: make [ clean | linux ]"
@echo
clean:
rm -f ./*.o
rm -f ./mtest
linux:
g++ -I../ $(FILES) -o mtest
rm -rf ./*.o

@ -0,0 +1,23 @@
Usage:
make linux
LD_PRELOAD=../liballoc.so ./mtest
.. and then just ..
./mtest
... to compare the results between liballoc and
the default malloc/free implementations ...
This is an arbitrary test which does not simulate real-life
events enough to fully guage the performance of the library.
However, it's primarily used to test correctness.

@ -0,0 +1,24 @@
#include <stdlib.h>
#include <stdio.h>
extern int malloc_test( int verbose );
int main( int argc, char *argv )
{
int verbose = 0;
if ( argc > 1 ) verbose = 1;
printf("%s\n","memory testing application" );
malloc_test( verbose );
printf("%s\n","all tests passed!");
return EXIT_SUCCESS;
}

@ -0,0 +1,195 @@
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
#define MAX_BLOCKS 100
#define MAX_SIZE (1024 * 1024)
#define MAX_TIME ( 1 * 60 )
/** A testing block to hold all allocated data. */
struct block
{
unsigned char *data;
int size;
unsigned char key;
};
/** The testing blocks. */
static struct block blocks[ MAX_BLOCKS ];
static long long totalMemory = 0;
static int totalBlocks = 0;
static int g_verbose = 0;
static int malloc_random( int verbose )
{
g_verbose = verbose;
totalMemory = 0;
totalBlocks = 0;
printf("malloc_random: this will take %i minute...\n", MAX_TIME/ 60 );
for ( int i = 0; i < MAX_BLOCKS; i++ )
{
blocks[ i ].data = NULL;
blocks[ i ].size = 0;
blocks[ i ].key = 0;
}
int transactions = 0;
time_t start_time = time(NULL);
// Random madness.
while (1==1)
{
int position = rand() % MAX_BLOCKS;
int diff = time(NULL) - start_time;
if ( diff > ( MAX_TIME ) ) break;
int tps = (++transactions) / (diff + 1);
if ( blocks[position].data == NULL )
{
blocks[position].size = rand() % MAX_SIZE;
blocks[position].data = (unsigned char*)malloc( blocks[position].size );
blocks[position].key = rand() % 256;
if ( g_verbose != 0 )
printf("%i left, %i tps : %i, %i : %i: allocating %i bytes with %i key\n",
( MAX_TIME - diff ),
tps,
totalBlocks * 100 / MAX_BLOCKS,
(int)(totalMemory / (1024)),
position,
blocks[position].size,
blocks[position].key );
if ( blocks[position].data != NULL )
{
totalMemory += blocks[position].size;
totalBlocks += 1;
for ( int j = 0; j < blocks[position].size; j++ )
blocks[position].data[j] = blocks[position].key;
}
}
else
{
for ( int j = 0; j < blocks[position].size; j++ )
if ( blocks[position].data[j] != blocks[position].key )
{
printf( "%i: %x (%i bytes, position %i) %i != %i: ERROR! Memory not consistent",
position,
blocks[position].data,
blocks[position].size,
j,
blocks[position].data[j],
blocks[position].key );
abort();
}
if ( g_verbose != 0 )
printf("%i left, %i tps : %i, %i : %i: freeing %i bytes with %i key\n",
( MAX_TIME - diff ),
tps,
totalBlocks * 100 / MAX_BLOCKS,
(int)(totalMemory / (1024)),
position,
blocks[position].size,
blocks[position].key );
free( blocks[position].data );
blocks[position].data = NULL;
totalMemory -= blocks[position].size;
totalBlocks -= 1;
}
}
// Dump the memory map here.
// Free.
for ( int i = 0; i < MAX_BLOCKS; i++ )
{
if ( blocks[ i ].data != NULL ) free( blocks[ i ].data );
blocks[ i ].size = 0;
blocks[ i ].key = 0;
}
// Final results.
printf("%i TPS, %i%s USAGE\n", transactions / MAX_TIME, totalBlocks * 100 / MAX_BLOCKS, "%" );
return 0;
}
static int malloc_large( int verbose )
{
g_verbose = verbose;
printf("malloc_large: going to exhaust the memory...\n" );
for ( int i = 0; i < MAX_BLOCKS; i++ )
blocks[ i ].data = NULL;
int transactions = 0;
time_t start_time = time(NULL);
for ( int i = 0; i < MAX_BLOCKS; i++ )
{
blocks[ i ].data = (unsigned char*)malloc( MAX_SIZE );
if ( blocks[i].data == NULL ) break;
transactions += 1;
}
for ( int i = 0; i < MAX_BLOCKS; i++ )
if ( blocks[ i ].data != NULL ) free( blocks[ i ].data );
// Final results.
printf("%i blocks of %i size = %i MB, %i seconds\n",
transactions,
MAX_SIZE,
(transactions * MAX_SIZE) / (1024 * 1024),
time(NULL) - start_time
);
return 0;
}
int malloc_test( int verbose )
{
malloc_random( verbose );
malloc_random( verbose );
malloc_random( verbose );
malloc_large( verbose );
malloc_large( verbose );
malloc_large( verbose );
return 0;
}
Loading…
Cancel
Save