diff options
author | neal <neal> | 2008-06-18 15:05:31 +0000 |
---|---|---|
committer | neal <neal> | 2008-06-18 15:05:31 +0000 |
commit | 3e9b30afc08a12f1f9f834e63578252b57bf9bfa (patch) | |
tree | 9c2c5451b5d98920953835207839c5bbb1915415 /benchmarks | |
parent | a3d002721fbb175163031e783aeba43de94ad9de (diff) |
2008-06-18 Neal H. Walfield <neal@gnu.org>
* Makefile.am (boot_PROGRAMS): Add gcbench.
(gcbench_CPPFLAGS): New variable.
(gcbench_CPPFLAGS): Likewise.
(gcbench_CPPFLAGS): Likewise.
(gcbench_CPPFLAGS): Likewise.
(gcbench_CPPFLAGS): Likewise.
Diffstat (limited to 'benchmarks')
-rw-r--r-- | benchmarks/ChangeLog | 9 | ||||
-rw-r--r-- | benchmarks/GCbench.c | 324 | ||||
-rw-r--r-- | benchmarks/Makefile.am | 8 |
3 files changed, 340 insertions, 1 deletions
diff --git a/benchmarks/ChangeLog b/benchmarks/ChangeLog index dabe13a..7889549 100644 --- a/benchmarks/ChangeLog +++ b/benchmarks/ChangeLog @@ -1,3 +1,12 @@ +2008-06-18 Neal H. Walfield <neal@gnu.org> + + * Makefile.am (boot_PROGRAMS): Add gcbench. + (gcbench_CPPFLAGS): New variable. + (gcbench_CPPFLAGS): Likewise. + (gcbench_CPPFLAGS): Likewise. + (gcbench_CPPFLAGS): Likewise. + (gcbench_CPPFLAGS): Likewise. + 2008-06-16 Neal H. Walfield <neal@gnu.org> * activity-distribution.c (main): Update use of diff --git a/benchmarks/GCbench.c b/benchmarks/GCbench.c new file mode 100644 index 0000000..603213e --- /dev/null +++ b/benchmarks/GCbench.c @@ -0,0 +1,324 @@ +/* Taken from: + http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_bench/GCBench.c. + Last modified: 26-Apr-2000 11:30. md5sum: + 1ddd6be7a929a8dbbf3e8b26b5e46a3d . */ + +#define GC +// This is adapted from a benchmark written by John Ellis and Pete Kovac +// of Post Communications. +// It was modified by Hans Boehm of Silicon Graphics. +// Translated to C++ 30 May 1997 by William D Clinger of Northeastern Univ. +// Translated to C 15 March 2000 by Hans Boehm, now at HP Labs. +// +// This is no substitute for real applications. No actual application +// is likely to behave in exactly this way. However, this benchmark was +// designed to be more representative of real applications than other +// Java GC benchmarks of which we are aware. +// It attempts to model those properties of allocation requests that +// are important to current GC techniques. +// It is designed to be used either to obtain a single overall performance +// number, or to give a more detailed estimate of how collector +// performance varies with object lifetimes. It prints the time +// required to allocate and collect balanced binary trees of various +// sizes. Smaller trees result in shorter object lifetimes. Each cycle +// allocates roughly the same amount of memory. +// Two data structures are kept around during the entire process, so +// that the measured performance is representative of applications +// that maintain some live in-memory data. One of these is a tree +// containing many pointers. The other is a large array containing +// double precision floating point numbers. Both should be of comparable +// size. +// +// The results are only really meaningful together with a specification +// of how much memory was used. It is possible to trade memory for +// better time performance. This benchmark should be run in a 32 MB +// heap, though we don't currently know how to enforce that uniformly. +// +// Unlike the original Ellis and Kovac benchmark, we do not attempt +// measure pause times. This facility should eventually be added back +// in. There are several reasons for omitting it for now. The original +// implementation depended on assumptions about the thread scheduler +// that don't hold uniformly. The results really measure both the +// scheduler and GC. Pause time measurements tend to not fit well with +// current benchmark suites. As far as we know, none of the current +// commercial Java implementations seriously attempt to minimize GC pause +// times. + +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> + +#ifdef GC +# include <gc/gc.h> +#endif + +#include <assert.h> + +#if 0 +#define DEBUG(fmt, ...) +#else +#define DEBUG(fmt, ...) printf (fmt, ##__VA_ARGS__) +#endif + +#ifdef PROFIL + extern void init_profiling(); + extern dump_profile(); +#endif + +// These macros were a quick hack for the Macintosh. +// +// #define currentTime() clock() +// #define elapsedTime(x) ((1000*(x))/CLOCKS_PER_SEC) + +#define currentTime() stats_rtclock() +#define elapsedTime(x) (x) + +/* Get the current time in milliseconds */ + +unsigned +stats_rtclock( void ) +{ + struct timeval t; + struct timezone tz; + + if (gettimeofday( &t, &tz ) == -1) + return 0; + return (t.tv_sec * 1000 + t.tv_usec / 1000); +} + +static const int kStretchTreeDepth = 18; // about 16Mb +static const int kLongLivedTreeDepth = 16; // about 4Mb +static const int kArraySize = 500000; // about 4Mb +static const int kMinTreeDepth = 4; +static const int kMaxTreeDepth = 16; + +typedef struct Node0_struct { + struct Node0_struct * left; + struct Node0_struct * right; + int i, j; +} Node0; + +#ifdef HOLES +# define HOLE() GC_NEW(Node0); +#else +# define HOLE() +#endif + +typedef Node0 *Node; + +void init_Node(Node me, Node l, Node r) { + me -> left = l; + me -> right = r; +} + +#ifndef GC + void destroy_Node(Node me) { + if (me -> left) { + destroy_Node(me -> left); + } + if (me -> right) { + destroy_Node(me -> right); + } + free(me); + } +#endif + +// Nodes used by a tree of a given size +static int TreeSize(int i) { + return ((1 << (i + 1)) - 1); +} + +// Number of iterations to use for a given tree depth +static int NumIters(int i) { + return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i); +} + +// Build tree top down, assigning to older objects. +static void Populate(int iDepth, Node thisNode) { + if (iDepth<=0) { + return; + } else { + iDepth--; +# ifdef GC + thisNode->left = GC_NEW(Node0); HOLE(); + thisNode->right = GC_NEW(Node0); HOLE(); +# else + thisNode->left = calloc(1, sizeof(Node0)); + thisNode->right = calloc(1, sizeof(Node0)); +# endif + Populate (iDepth, thisNode->left); + Populate (iDepth, thisNode->right); + } +} + +// Build tree bottom-up +static Node MakeTree(int iDepth) { + Node result; + if (iDepth<=0) { +# ifndef GC + result = calloc(1, sizeof(Node0)); +# else + result = GC_NEW(Node0); HOLE(); +# endif + assert (result); + /* result is implicitly initialized in both cases. */ + return result; + } else { + Node left = MakeTree(iDepth-1); + Node right = MakeTree(iDepth-1); +# ifndef GC + result = malloc(sizeof(Node0)); +# else + result = GC_NEW(Node0); HOLE(); +# endif + assert (result); + init_Node(result, left, right); + return result; + } +} + +static void PrintDiagnostics() { +#if 0 + long lFreeMemory = Runtime.getRuntime().freeMemory(); + long lTotalMemory = Runtime.getRuntime().totalMemory(); + + System.out.print(" Total memory available=" + + lTotalMemory + " bytes"); + System.out.println(" Free memory=" + lFreeMemory + " bytes"); +#endif +} + +static void TimeConstruction(int depth) { + long tStart, tFinish; + int iNumIters = NumIters(depth); + Node tempTree; + int i; + + DEBUG("Creating %d trees of depth %d\n", iNumIters, depth); + + tStart = currentTime(); + for (i = 0; i < iNumIters; ++i) { +# ifndef GC + tempTree = calloc(1, sizeof(Node0)); +# else + tempTree = GC_NEW(Node0); +# endif + Populate(depth, tempTree); +# ifndef GC + destroy_Node(tempTree); +# endif + tempTree = 0; + } + tFinish = currentTime(); + DEBUG("\tTop down construction took %ld msec\n", + elapsedTime(tFinish - tStart)); + + tStart = currentTime(); + for (i = 0; i < iNumIters; ++i) { + tempTree = MakeTree(depth); +# ifndef GC + destroy_Node(tempTree); +# endif + tempTree = 0; + } + tFinish = currentTime(); + DEBUG("\tBottom up construction took %ld msec\n", + elapsedTime(tFinish - tStart)); + +} + +int main() { + extern int GC_print_stats; + // GC_print_stats = 1; + + Node root; + Node longLivedTree; + Node tempTree; + long tStart, tFinish; + long tElapsed; + int i, d; + double *array; + +#ifdef GC + // GC_full_freq = 30; + // GC_free_space_divisor = 16; + // GC_enable_incremental(); +#endif + printf("Garbage Collector Test\n"); + printf(" Live storage will peak at %d bytes.\n\n", + 2 * sizeof(Node0) * TreeSize(kLongLivedTreeDepth) + + sizeof(double) * kArraySize); + printf(" Stretching memory with a binary tree of depth %d\n", + kStretchTreeDepth); + PrintDiagnostics(); +# ifdef PROFIL + init_profiling(); +# endif + + tStart = currentTime(); + + // Stretch the memory space quickly + tempTree = MakeTree(kStretchTreeDepth); +# ifndef GC + destroy_Node(tempTree); +# endif + tempTree = 0; + + // Create a long lived object + DEBUG(" Creating a long-lived binary tree of depth %d\n", + kLongLivedTreeDepth); +# ifndef GC + longLivedTree = calloc(1, sizeof(Node0)); +# else + longLivedTree = GC_NEW(Node0); +# endif + Populate(kLongLivedTreeDepth, longLivedTree); + + // Create long-lived array, filling half of it + DEBUG(" Creating a long-lived array of %d doubles\n", kArraySize); +# ifndef GC + array = malloc(kArraySize * sizeof(double)); +# else +# ifndef NO_PTRFREE + array = GC_MALLOC_ATOMIC(sizeof(double) * kArraySize); +# else + array = GC_MALLOC(sizeof(double) * kArraySize); +# endif +# endif + for (i = 0; i < kArraySize/2; ++i) { + array[i] = 1.0/i; + } + PrintDiagnostics(); + +#define ITERATIONS 100 + int j; + for (j = 0; j < ITERATIONS; j ++) + { + DEBUG ("Iteration %d\n", j); + for (d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2) { + TimeConstruction(d); + } + } + + + if (longLivedTree == 0 || array[1000] != 1.0/1000) + fprintf(stderr, "Failed\n"); + // fake reference to LongLivedTree + // and array + // to keep them from being optimized away + tFinish = currentTime(); + tElapsed = elapsedTime(tFinish-tStart); + PrintDiagnostics(); + printf("Completed in %ld.%03ld sec\n", + tElapsed / 1000, tElapsed % 1000); +# ifdef GC + { + extern void GC_dump_stats (void); + GC_dump_stats (); + } +# endif +# ifdef PROFIL + dump_profile(); +# endif +} + diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am index ac5dc11..a68bae7 100644 --- a/benchmarks/Makefile.am +++ b/benchmarks/Makefile.am @@ -22,7 +22,7 @@ bootdir = $(prefix)/boot if ! ENABLE_TESTS SUBDIRS = boehm-gc -boot_PROGRAMS = shared-memory-distribution activity-distribution +boot_PROGRAMS = shared-memory-distribution activity-distribution gcbench endif shared_memory_distribution_CPPFLAGS = $(USER_CPPFLAGS) @@ -37,3 +37,9 @@ activity_distribution_LDFLAGS = $(USER_LDFLAGS) activity_distribution_LDADD = $(USER_LDADD) activity_distribution_SOURCES = activity-distribution.c +gcbench_CPPFLAGS = $(USER_CPPFLAGS) -Iboehm-gc/gc-install/include +gcbench_CFLAGS = $(USER_CFLAGS) +gcbench_LDFLAGS = $(USER_LDFLAGS) -Lboehm-gc/gc-install/lib +gcbench_LDADD = -lgc $(USER_LDADD) +gcbench_SOURCES = GCbench.c + |