home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
mallocte.zip
/
MALLOC.CPP
next >
Wrap
C/C++ Source or Header
|
1996-08-29
|
9KB
|
406 lines
// $Id$
//
// Copyright (c) 1996 Tarma Software Research. All rights reserved.
//
// Project: C++ compiler tests
// Author: Ron van der Wal
// Created: 31-07-1996 16:45
//
// Test program for speed of memory allocation routines.
//
// Original: Arthur D. Applegate: "Rethinking Memory Management",
// Dr. Dobb's Journal, June 1994, pp. 52-55.
//
//! Usage: MALLOC [iters [maxblock [minblock]]]
// Usage: MALLOC [total [maxblock [minblock]]]
//
// Output format in CSV files
// --------------------------
//! "Compiler name",iters,minblock,maxblock,insertion,search,deletion
// "Compiler name",total,minblock,maxblock,insertion,search,deletion,alloc,count
#include <assert.h>
#include <fstream.h>
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
//#define WITH_BUCKETS // Define to use frequency distribution buckets
//#define WITH_BUGS // Define to insert bugs
// Compiler names
#define _STR(x) #x
#define STR(x) _STR(x)
#if defined(__BORLANDC__)
const char gCCName[] = "Borland C++ " STR(__BORLANDC__);
#elif defined(__IBMCPP__)
const char gCCName[] = "IBM CSet++ " STR(__IBMCPP__);
#elif defined(_MSC_VER)
const char gCCName[] = "Microsoft C++ " STR(_MSC_VER);
#elif defined(__SC__)
const char gCCName[] = "Symantec C++ " STR(__SC__);
#elif defined(__WATCOMC__)
const char gCCName[] = "Watcom C++ " STR(__WATCOMC__);
#else
#error Unknown compiler
#endif
// CSV output file
ostream *gCSV = 0;
// Random range
const int cMaxMaxBlock = 4096; // Absolute maximum
int gMinBlock = 1; // Default minimum block size
int gMaxBlock = 512; // Default maximum block size
long gNoIters = 1000; // Default number of iterations
long gMaxAlloc = 1000000L; // Default total allocation size
long gTotalAlloc = 0; // Size of allocations thus far
long gTotalCount = 0; // Number of allocations thus far
#ifdef WITH_BUCKETS
// Global buckets variable
class Buckets;
Buckets *gBuckets = 0;
#endif
// Minimal standard RNG (see Numerical Recipes).
double Rand0()
{
static long _gSeed = 0;
const long IA = 16807L;
const long IM = 2147483647L;
const double AM = 1.0 / IM;
const long IQ = 127773L;
const long IR = 2836L;
const long MASK = 123459876L;
_gSeed ^= MASK;
long k = _gSeed / IQ;
_gSeed = IA * (_gSeed - k * IQ) - IR * k;
if (_gSeed < 0) _gSeed += IM;
double result = AM * _gSeed;
_gSeed ^= MASK;
return result;
}
// Define the following to use standard rand() generator
//#define USE_STANDARD 1
#ifdef USE_STANDARD
#define rng() ((double)rand()/(RAND_MAX + 1L))
#else
#define rng() Rand0()
#endif
// Generate random number in certain range. Modulo operator is not used,
// since it would lead to non-uniformly distributed values.
inline int RandBetween(int aLow, int aHigh)
{
#ifdef WITH_BUGS
return (int)(rng() * (aHigh - aLow + 2)) + aLow;
#else // WITH_BUGS
#ifdef NDEBUG
return (int)(rng() * (aHigh - aLow + 1)) + aLow;
#else
int result = (int)(rng() * (aHigh - aLow + 1)) + aLow;
assert(result >= aLow);
assert(result <= aHigh);
return result;
#endif // NDEBUG
#endif // WITH_BUGS
}
#ifdef WITH_BUCKETS
// Buckets to remember frequency distributions
class Buckets
{
int * mBuckets; // Array of buckets
int mSize; // Number of buckets
int mLow; // Lower bound
// Statistics
long mCount;
long mSum;
long mSumSquare;
public:
Buckets(int aLow, int aHigh);
~Buckets();
// Bucket operations
void AddValue(int);
void Clear();
// Bucket statistics
long Count() const { return mCount; }
long Sum() const { return mSum; }
long Average() const { return mCount ? mSum / mCount : 0; }
// Output operations
void Print(ostream &) const;
};
Buckets::Buckets(int aLow, int aHigh)
{
assert(aLow <= aHigh);
mLow = aLow;
mSize = aHigh - aLow + 1;
mBuckets = new int[mSize];
Clear();
}
Buckets::~Buckets()
{
delete [] mBuckets;
}
void Buckets::AddValue(int aValue)
{
#ifndef WITH_BUGS
assert(mLow <= aValue && aValue < mLow + mSize);
#endif
++mBuckets[aValue - mLow];
// Update statistics
++mCount;
mSum += aValue;
mSumSquare += aValue * aValue;
}
void Buckets::Clear()
{
memset(mBuckets, 0, sizeof(int) * mSize);
mCount = mSum = mSumSquare = 0;
}
void Buckets::Print(ostream &os) const
{
os << mCount << " values, average = " << Average() << ", sum = "
<< Sum() << ", Frequencies:\n";
for (int i = 0; i < mSize; ++i)
os << setw(8) << (i + mLow) << ": " << mBuckets[i] << "\n";
}
#endif // WITH_BUCKETS
class Timer
{
const char *m;
clock_t startTime;
public:
Timer(const char *msg): m(msg), startTime(clock()) {}
~Timer()
{
double elapsed = ((double)(clock() - startTime) /
(double)CLOCKS_PER_SEC);
cout << m << ": " << elapsed << " seconds.\n";
if (gCSV) *gCSV << "," << elapsed;
}
};
class Link
{
friend class List;
char *value;
Link *prev, *next;
public:
Link(const char *, Link *, Link *);
~Link();
};
class List
{
Link *head, *tail;
public:
List();
~List();
Link * Insert(Link *, const char *);
void Delete(Link *);
void RandomOp();
const Link * Find(const char *) const;
};
Link::Link(const char *val, Link *p, Link *n)
{
value = new char[strlen(val) + 1];
strcpy(value, val);
if ((prev = p) != 0) prev->next = this;
if ((next = n) != 0) next->prev = this;
}
Link::~Link()
{
delete [] value; // Original omitted []
if (prev) prev->next = next;
if (next) next->prev = prev;
}
List::List()
{
head = tail = 0;
}
List::~List()
{
while (head)
Delete(head);
}
Link *List::Insert(Link *prev, const char *val)
{
Link *next = prev ? prev->next : head;
Link *l = new Link(val, prev, next);
if (!prev) head = l;
if (!next) tail = l;
return l;
}
void List::Delete(Link *l)
{
if (!l) return;
if (head == l) head = l->next;
if (tail == l) tail = l->prev;
delete l;
}
void List::RandomOp()
{
if (rng() < 0.8)
{
static char buf[cMaxMaxBlock + 1];
int len = RandBetween(gMinBlock, gMaxBlock);
#ifdef WITH_BUCKETS
gBuckets->AddValue(len);
#endif
memset(buf, RandBetween(1, 127), len);
buf[len] = 0;
Insert(tail, buf);
gTotalAlloc += len;
++gTotalCount;
}
else
Delete(head);
}
const Link *List::Find(const char *val) const
{
for (Link *l = head; l; l = l->next)
{
if (strcmp(l->value, val) == 0)
break;
}
return l;
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
//! cout << "usage: MALLOC iters [maxblock [minblock]]\n";
cout << "usage: MALLOC total [maxblock [minblock]]\n";
return -1;
}
gCSV = new ofstream("malloc.csv", ios::out | ios::app);
//! if (argc >= 2)
//! gNoIters = atol(argv[1]);
if (argc >= 2)
gMaxAlloc = atol(argv[1]);
if (argc >= 3)
gMaxBlock = atoi(argv[2]);
if (argc >= 4)
gMinBlock = atoi(argv[3]);
//! cout << "Test parameters: iterations=" << gNoIters << ", maxblock="
//! << gMaxBlock << ", minblock=" << gMinBlock << "\n";
//! if (gCSV)
//! *gCSV << "\"" << gCCName << "\"," << gNoIters << "," << gMaxBlock
//! << "," << gMinBlock;
cout << "Test parameters: max alloc=" << gMaxAlloc << ", maxblock="
<< gMaxBlock << ", minblock=" << gMinBlock << "\n";
if (gCSV)
*gCSV << "\"" << gCCName << "\"," << gMaxAlloc << "," << gMaxBlock
<< "," << gMinBlock;
#ifdef WITH_BUCKETS
// Create buckets for correct range
gBuckets = new Buckets(gMinBlock, gMaxBlock);
#endif
Timer t("Overall application");
List *list1 = new List, *list2 = new List, *list3 = new List,
*list4 = new List, *list5 = new List;
{
Timer t("Insertion");
//! while (gTotalCount < gNoIters)
while (gTotalAlloc < gMaxAlloc)
{
list1->RandomOp();
list2->RandomOp();
list3->RandomOp();
list4->RandomOp();
list5->RandomOp();
}
}
{
Timer t("Search");
list1->Find("not present");
list2->Find("not present");
list3->Find("not present");
list4->Find("not present");
list5->Find("not present");
}
{
Timer t("Deletion");
delete list1;
delete list2;
delete list3;
delete list4;
delete list5;
}
cout << "Total allocated size: " << gTotalAlloc << "\nTotal # blocks: "
<< gTotalCount << "\n";
if (gCSV) *gCSV << "," << gTotalAlloc << "," << gTotalCount << "\n";
#ifdef WITH_BUCKETS
gBuckets->Print(cout);
#endif
#ifndef WITH_BUGS
#ifdef WITH_BUCKETS
delete gBuckets;
gBuckets = 0;
#endif // WITH_BUCKETS
#endif // WITH_BUGS
delete gCSV;
gCSV = 0;
return 0;
}