Skip to content

Commit

Permalink
Added allocator scaling test
Browse files Browse the repository at this point in the history
  • Loading branch information
Niall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) committed Jul 14, 2010
1 parent 2743c75 commit f3624af
Show file tree
Hide file tree
Showing 7 changed files with 548 additions and 3 deletions.
Binary file added ScalingTestResults.xlsx
Binary file not shown.
2 changes: 2 additions & 0 deletions nedmalloc.c
Expand Up @@ -1829,7 +1829,9 @@ static NOINLINE void GetThreadCache_cold2(nedpool *RESTRICT *RESTRICT p, threadc
static FORCEINLINE void GetThreadCache(nedpool *RESTRICT *RESTRICT p, threadcache *RESTRICT *RESTRICT tc, int *RESTRICT mymspace, size_t *RESTRICT size) THROWSPEC
{
int mycache;
#if THREADCACHEMAX
if(size && *size<sizeof(threadcacheblk)) *size=sizeof(threadcacheblk);
#endif
if(!*p)
GetThreadCache_cold1(p);
mycache=(int)(size_t) TLSGET((*p)->mycache);
Expand Down
8 changes: 8 additions & 0 deletions nedmalloc.sln
Expand Up @@ -12,6 +12,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nedmalloc_test_c", "nedmall
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nedmalloc_test_cpp", "nedmalloc_test_cpp.vcproj", "{889F56B1-6231-458A-84BB-F2AAF302FF7D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scalingtest", "scalingtest.vcproj", "{C18CA5F2-FCAA-4D28-8FAB-5DF60E78AE9E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Expand Down Expand Up @@ -52,6 +54,12 @@ Global
{889F56B1-6231-458A-84BB-F2AAF302FF7D}.Release|Win32.Build.0 = Release|Win32
{889F56B1-6231-458A-84BB-F2AAF302FF7D}.Release|x64.ActiveCfg = Release|x64
{889F56B1-6231-458A-84BB-F2AAF302FF7D}.Release|x64.Build.0 = Release|x64
{C18CA5F2-FCAA-4D28-8FAB-5DF60E78AE9E}.Debug|Win32.ActiveCfg = Debug|Win32
{C18CA5F2-FCAA-4D28-8FAB-5DF60E78AE9E}.Debug|Win32.Build.0 = Debug|Win32
{C18CA5F2-FCAA-4D28-8FAB-5DF60E78AE9E}.Debug|x64.ActiveCfg = Debug|Win32
{C18CA5F2-FCAA-4D28-8FAB-5DF60E78AE9E}.Release|Win32.ActiveCfg = Release|Win32
{C18CA5F2-FCAA-4D28-8FAB-5DF60E78AE9E}.Release|Win32.Build.0 = Release|Win32
{C18CA5F2-FCAA-4D28-8FAB-5DF60E78AE9E}.Release|x64.ActiveCfg = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
179 changes: 179 additions & 0 deletions scalingtest.cpp
@@ -0,0 +1,179 @@
/* scalingtest.cpp
Tests how various allocators scale according to block size using a monte-carlo approach
(C) 2010 Niall Douglas
*/

#define FORCEINLINE
#define NOINLINE
//#define THREADCACHEMAX 0
//#pragma optimize("g", off)

#include "nedmalloc.c"
#include <math.h>
#include <vector>

#define LOOPS 25000
#define MAXBLOCKSIZE (8*1024*1024)

#ifdef WIN32
typedef unsigned __int64 usCount;
static usCount GetUsCount()
{
static LARGE_INTEGER ticksPerSec;
static double scalefactor;
LARGE_INTEGER val;
if(!scalefactor)
{
if(QueryPerformanceFrequency(&ticksPerSec))
scalefactor=ticksPerSec.QuadPart/1000000000000.0;
else
scalefactor=1;
}
if(!QueryPerformanceCounter(&val))
return (usCount) GetTickCount() * 1000000000;
return (usCount) (val.QuadPart/scalefactor);
}
#else
#include <sys/time.h>

typedef unsigned long long usCount;
static usCount GetUsCount()
{
#ifdef CLOCK_MONOTONIC
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ((usCount) ts.tv_sec*1000000000000LL)+ts.tv_nsec*1000LL;
#else
struct timeval tv;
gettimeofday(&tv, 0);
return ((usCount) tv.tv_sec*1000000000000LL)+tv.tv_usec*1000000LL;
#endif
}
#endif

template<void (*_free)(void *)> void wrapfree(void *mem, size_t size)
{
_free(mem);
}
static void *mmap_wrapper(size_t size)
{
#ifdef WIN32
return VirtualAlloc(NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
#else
return mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
#endif
}
static void munmap_wrapper(void *mem, size_t size)
{
#ifdef WIN32
VirtualFree(mem, 0, MEM_RELEASE);
#else
munmap(mem, size);
#endif
}
static void *userpagemalloc_wrapper(size_t size)
{
return userpage_malloc(size, 0);
}
static void userpagefree_wrapper(void *mem, size_t size)
{
userpage_free(mem, size);
}
static mspace mymspace = create_mspace(0,0);
static void *dlmalloc(size_t size)
{
return mspace_malloc(mymspace, size);
}
static void dlfree(void *mem, size_t size)
{
mspace_free(mymspace, mem);
}

struct Allocator
{
const char *name, *shortname;
size_t minsize, minsizeshift;
void *(*malloc)(size_t);
void (*free)(void *, size_t);
};
static Allocator allocators[]={
{ "System allocator", "sysalloc", 0, 0, &malloc, &wrapfree<free> },
{ "nedmalloc", "nedmalloc", 0, 0, &nedalloc::nedmalloc, &wrapfree<nedalloc::nedfree> },
{ "dlmalloc", "dlmalloc", 0, 0, &dlmalloc, &dlfree },
#ifndef WIN32
{ "System mmap()", "sysmmap", PAGE_SIZE, 0, &mmap_wrapper, &munmap_wrapper },
#else
{ "System VirtualAlloc()", "sysmmap", PAGE_SIZE, 0, &mmap_wrapper, &munmap_wrapper },
#endif
{ "User mode page allocator", "usermodemmap", PAGE_SIZE, 0, &userpagemalloc_wrapper, &userpagefree_wrapper }
};

int main(void)
{
using namespace std;
printf("What would you like to test?\n");
for(int n=0; n<sizeof(allocators)/sizeof(Allocator); n++)
{
printf(" %d. %s\n", n+1, allocators[n].name);
}
int allocatoridx=getchar()-'1';
if(allocatoridx<0 || allocatoridx>sizeof(allocators)/sizeof(Allocator)) return 1;
Allocator &allocator=allocators[allocatoridx];
allocator.minsizeshift=allocator.minsize ? nedtriebitscanr(allocator.minsize) : (allocator.minsize=1<<3, 3);
printf("\nYou chose allocator %d (%s) with minsizeshift=%u\n", allocatoridx+1, allocator.name, allocator.minsizeshift);
for(usCount s=GetUsCount(); GetUsCount()-s<3000000000000ULL;);
printf("Testing ...\n");

vector<pair<usCount, size_t> > bins(nedtriebitscanr(MAXBLOCKSIZE)+1);
struct Ptrs_t { void *mem; size_t size; } ptrs[512], *ptrp;
memset(ptrs, 0, sizeof(ptrs));
ptrp=ptrs;
for(int n=0; n<LOOPS; n++)
{
size_t blksize;
do
{
double randval=(double) rand()/(RAND_MAX/(8*sizeof(size_t)))+allocator.minsizeshift;
blksize=((size_t) pow(2, randval)) & (MAXBLOCKSIZE-1);
blksize&=~(allocator.minsize-1);
} while(blksize<allocator.minsize);
usCount start, end;
if(n>LOOPS/2 && blksize<32)
{
int a=1;
}
if(ptrp->mem)
{
start=GetUsCount();
allocator.free(ptrp->mem, ptrp->size);
end=GetUsCount();
//pair<usCount, size_t> &v=bins[nedtriebitscanr(ptrp->size)];
//v.first+=end-start;
//v.second++;
ptrp->mem=0; ptrp->size=0;
}
start=GetUsCount();
ptrp->mem=allocator.malloc(blksize);
ptrp->size=blksize;
for(volatile char *p=(volatile char *)ptrp->mem, *pend=(volatile char *)ptrp->mem+blksize; p<pend; p+=PAGE_SIZE)
*p;
end=GetUsCount();
if(++ptrp==ptrs+512) ptrp=ptrs;
pair<usCount, size_t> &v=bins[blksize ? nedtriebitscanr(blksize) : 0];
v.first+=end-start;
v.second++;
}
char filename[256];
sprintf(filename, "scalingtest_%s.csv", allocator.shortname);
printf("\nWriting results to %s ...\n", filename);
FILE *oh=fopen(filename, "w");
fprintf(oh, "Bin,Latency,Count\n");
int n=0;
for(vector<pair<usCount, size_t> >::const_iterator it=bins.begin(); it!=bins.end(); ++it, n++)
{
fprintf(oh, "%u,%f,%u\n", 1<<n, (double) it->first/it->second, it->second);
}
fclose(oh);
printf("Done!\n");
return 0;
}

0 comments on commit f3624af

Please sign in to comment.