diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | benchmarks/ChangeLog | 6 | ||||
-rw-r--r-- | benchmarks/Makefile.am | 39 | ||||
-rw-r--r-- | benchmarks/activity-distribution.c | 203 | ||||
-rw-r--r-- | benchmarks/boehm-gc/ChangeLog | 6 | ||||
-rw-r--r-- | benchmarks/boehm-gc/Makefile.am | 117 | ||||
-rw-r--r-- | benchmarks/boehm-gc/patches/01-gc-include-private-gcconfig-h.patch | 17 | ||||
-rw-r--r-- | benchmarks/boehm-gc/patches/02-gc-mach_dep-c.patch | 18 | ||||
-rw-r--r-- | benchmarks/shared-memory-distribution.c | 148 | ||||
-rw-r--r-- | configure.ac | 2 |
11 files changed, 564 insertions, 0 deletions
@@ -1,3 +1,10 @@ +2008-05-30 Neal H. Walfield <neal@gnu.org> + + * benchmarks: New directory. + * configure.ac: Generate benchmarks/Makefile and + benchmarks/boehm-gc/Makefile. + * Makefile.am (SUBDIRS): Add benchmarks. + 2008-05-30 Thomas Schwinge <tschwinge@gnu.org> * configure.ac (missing_progs): Rename to... diff --git a/Makefile.am b/Makefile.am index 611d5cf..c8de915 100644 --- a/Makefile.am +++ b/Makefile.am @@ -41,6 +41,7 @@ SUBDIRS = libl4 platform \ laden viengoos \ . \ ruth \ + benchmarks \ hieronymus \ $(DOC) endif diff --git a/benchmarks/ChangeLog b/benchmarks/ChangeLog new file mode 100644 index 0000000..314e4fb --- /dev/null +++ b/benchmarks/ChangeLog @@ -0,0 +1,6 @@ +2008-05-30 Neal H. Walfield <neal@gnu.org> + + * Makefile.am: New file. + * activity-distribution.c: Likewise. + * shared-memory-distribution.c: Likewise. + * boehm-gc: New directory. diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am new file mode 100644 index 0000000..ac5dc11 --- /dev/null +++ b/benchmarks/Makefile.am @@ -0,0 +1,39 @@ +# Makefile.am - Makefile template for hurd-l4. +# Copyright (C) 2008 Free Software Foundation, Inc. +# +# This file is part of the GNU Hurd. +# +# The GNU Hurd is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# The GNU Hurd is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +bootdir = $(prefix)/boot + +if ! ENABLE_TESTS +SUBDIRS = boehm-gc + +boot_PROGRAMS = shared-memory-distribution activity-distribution +endif + +shared_memory_distribution_CPPFLAGS = $(USER_CPPFLAGS) +shared_memory_distribution_CFLAGS = $(USER_CFLAGS) +shared_memory_distribution_LDFLAGS = $(USER_LDFLAGS) +shared_memory_distribution_LDADD = $(USER_LDADD) +shared_memory_distribution_SOURCES = shared-memory-distribution.c + +activity_distribution_CPPFLAGS = $(USER_CPPFLAGS) +activity_distribution_CFLAGS = $(USER_CFLAGS) +activity_distribution_LDFLAGS = $(USER_LDFLAGS) +activity_distribution_LDADD = $(USER_LDADD) +activity_distribution_SOURCES = activity-distribution.c + diff --git a/benchmarks/activity-distribution.c b/benchmarks/activity-distribution.c new file mode 100644 index 0000000..6ae89d4 --- /dev/null +++ b/benchmarks/activity-distribution.c @@ -0,0 +1,203 @@ +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/mman.h> +#include <errno.h> +#include <string.h> +#include <pthread.h> + +#include <hurd/activity.h> +#include <hurd/storage.h> +#include <hurd/startup.h> +#include <hurd/anonymous.h> + +static addr_t activity; + +/* Initialized by the machine-specific startup-code. */ +extern struct hurd_startup_data *__hurd_startup_data; + +#include <hurd/trace.h> + +int +main (int argc, char *argv[]) +{ + error_t err; + + extern int output_debug; + output_debug = 1; + + activity = __hurd_startup_data->activity; + + printf ("%s running...\n", argv[0]); + +#define THREADS 4 + + /* The activities. */ + addr_t activities[THREADS]; + + /* Create THREADS activities, each with an increasing weight. */ + int i; + for (i = 0; i < THREADS; i ++) + { + activities[i] = storage_alloc (activity, cap_activity, + STORAGE_LONG_LIVED, + OBJECT_POLICY_DEFAULT, + ADDR_VOID).addr; + + struct activity_policy in; + in.sibling_rel.weight = i + 1; + struct activity_policy out; + err = rm_activity_policy (activities[i], + ACTIVITY_POLICY_SIBLING_REL_WEIGHT_SET, in, + &out); + assert (err == 0); + } + + bool terminate = false; + l4_thread_id_t tids[THREADS]; + for (i = 0; i < THREADS; i ++) + tids[i] = l4_nilthread; + + int available; + { + int count; + struct activity_stats_buffer buffer; + + err = rm_activity_stats (activity, 1, &buffer, &count); + assert (err == 0); + assert (count > 0); + + available = buffer.stats[0].available * PAGESIZE; + } + printf ("%d kb memory available\n", available / 1024); + + bool my_fill (struct anonymous_pager *anon, + void *base, uintptr_t offset, + uintptr_t pages, + struct exception_info info) + { + * (int *) (base + offset) = 1; + return true; + } + + void *worker (void *arg) + { + int w = (intptr_t) arg; + + tids[w] = l4_myself (); + + pthread_setactivity_np (activities[w]); + + /* Object size. */ +#define SIZE (256 * PAGESIZE) + + /* The number of objects: set so that they fill half of the + available memory. */ +#define ITEMS (available / SIZE / 2) + + struct anonymous_pager *pagers[ITEMS]; + memset (pagers, 0, sizeof (pagers)); + void *buffers[ITEMS]; + memset (buffers, 0, sizeof (buffers)); + + int t = 0; + while (! terminate) + { + int i = rand () % ITEMS; + + if (! pagers[i]) + /* Allocate a (discardable) buffer. */ + { + pagers[i] + = anonymous_pager_alloc (ADDR_VOID, NULL, SIZE, + OBJECT_POLICY (true, + OBJECT_PRIORITY_LRU), + 0, my_fill, &buffers[i]); + assert (pagers[i]); + assert (buffers[i]); + } + + int j; + for (j = 0; j < SIZE / PAGESIZE; j ++) + t += * (int *) (buffers[i] + j * PAGESIZE); + + /* 100ms. */ + l4_sleep (l4_time_period (100 * 1000)); + } + + /* We need to return t, otherwise, the above loop will be + optimized away. */ + return (void *) t; + } + + /* Start the threads. */ + pthread_t threads[THREADS]; + + for (i = 0; i < THREADS; i ++) + { + err = pthread_create (&threads[i], NULL, worker, (void *) (intptr_t) i); + if (err) + printf ("Failed to create thread: %s\n", strerror (errno)); + } + +#define ITERATIONS 200 + struct activity_stats stats[ITERATIONS][1 + THREADS]; + + uintptr_t next_period = 0; + for (i = 0; i < ITERATIONS; i ++) + { + debug (0, DEBUG_BOLD ("starting iteration %d (%x)"), i, l4_myself ()); + + extern struct trace_buffer rwlock_trace; + trace_buffer_dump (&rwlock_trace, 20); + + int count; + struct activity_stats_buffer buffer; + + rm_activity_stats (activity, next_period, &buffer, &count); + assert (count > 0); + if (i != 0) + assertx (buffer.stats[0].period != stats[i - 1][0].period, + "%d == %d", + buffer.stats[0].period, stats[i - 1][0].period); + + stats[i][0] = buffer.stats[0]; + + int j; + for (j = 0; j < THREADS; j ++) + { + rm_activity_stats (activities[j], next_period, &buffer, &count); + assert (count > 0); + stats[i][1 + j] = buffer.stats[0]; + } + + next_period = stats[i][0].period + 1; + } + + terminate = true; + for (i = 0; i < THREADS; i ++) + { + void *status; + pthread_join (threads[i], &status); + } + + printf ("parent "); + for (i = 0; i < THREADS; i ++) + printf (ADDR_FMT " ", ADDR_PRINTF (activities[i])); + printf ("\n"); + + for (i = 0; i < ITERATIONS; i ++) + { + int j; + + printf ("%d ", (int) stats[i][0].period); + + for (j = 0; j < 1 + THREADS; j ++) + printf ("%d ", (int) stats[i][j].clean + (int) stats[i][j].dirty); + printf ("\n"); + } + + printf ("Done!\n"); + + return 0; +} diff --git a/benchmarks/boehm-gc/ChangeLog b/benchmarks/boehm-gc/ChangeLog new file mode 100644 index 0000000..bcd3436 --- /dev/null +++ b/benchmarks/boehm-gc/ChangeLog @@ -0,0 +1,6 @@ +2008-05-30 Neal H. Walfield <neal@gnu.org> + + * Makefile.am: New file. + * pathches: New directory. + * patches/01-gc-include-private-gcconfig-h.patch: New file. + * patches/02-gc-mach_dep-c.patch: New file. diff --git a/benchmarks/boehm-gc/Makefile.am b/benchmarks/boehm-gc/Makefile.am new file mode 100644 index 0000000..872992f --- /dev/null +++ b/benchmarks/boehm-gc/Makefile.am @@ -0,0 +1,117 @@ +# Makefile.am - Makefile template for the Boehm GC +# Copyright (C) 2008 Free Software Foundation, Inc. +# Written by Neal H. Walfield +# +# This file is part of the GNU Hurd. +# +# The GNU Hurd is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# The GNU Hurd is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +include $(top_srcdir)/Makefoo.am + +noinst_LIBRARIES = libgc.a + +# Patches to apply to the source tree. +patch_files = 01-gc-include-private-gcconfig-h.patch \ + 02-gc-mach_dep-c.patch + +# Files to link into newlib's source tree (relative to $(srcdir)/addon) +addon = + +EXTRA_DIST = $(addprefix patches/, $(patch_files)) \ + $(addprefix addon/, $(addon)) + +# The source tarball. +gc_tarball = gc-7.0.tar.gz +gc_snapshot = $(gc_tarball) + +# Grab the snapshot +$(srcdir)/$(gc_tarball): + wget $(gc_snapshot) -O $(srcdir)/$(gc_tarball) + +# Extract it. +$(srcdir)/gc/unpack.stamp: $(srcdir)/$(gc_tarball) + if test -e $(srcdir)/gc/.; then \ + echo "Refusing to extract over $(srcdir)/gc"; \ + exit 1; \ + fi + ( cd $(srcdir) \ + && tar xfvz $(gc_tarball) \ + && mv $(subst .tar.gz,,$(gc_tarball)) gc ) + touch $@ + +# Apply any local patches. (Revert any applied older version.) +$(addprefix $(srcdir)/gc/,$(addsuffix .applied,$(patch_files))): $(srcdir)/gc/unpack.stamp +$(addprefix $(srcdir)/gc/,$(addsuffix .applied,$(patch_files))): $(srcdir)/gc/%.applied: $(srcdir)/patches/% + if test -e "$@"; \ + then \ + ( cd $(srcdir)/gc && sh /dev/stdin -R ) < $@ && rm -f $@; \ + fi + ( cd $(srcdir)/gc && sh /dev/stdin ) < $< + cp $< $@ + +rpatch: + for p in $(shell tac -s ' ' $(patch_files)) ; do \ + (cd $(srcdir)/gc; sh ../$(srcdir)/$${p} -R) || exit 1 ; \ + done + +# Link the addon files into the source tree. +$(addprefix $(srcdir)/gc/, $(addon)): $(srcdir)/gc/unpack.stamp +$(addprefix $(srcdir)/gc/, $(addon)): $(srcdir)/gc/%: $(srcdir)/addon/% + mkdir -p $(dir $@) + $(LN_S) -f $(abspath $<) $@ +# Touch the file, as Make follows symlinks, the source file for sure is younger +# than the unpack.stamp and thus those files will get linked again and again. + touch $@ + +$(srcdir)/gc/patch.stamp: $(srcdir)/gc/unpack.stamp \ + $(addprefix $(srcdir)/gc/,$(addsuffix .applied,$(patch_files))) \ + $(addprefix $(srcdir)/gc/,$(addon)) + cd $(srcdir)/gc/ \ + && $(fix_config_guess_and_sub) \ + && autoreconf + touch $@ + +gc-build/configure-stamp: $(srcdir)/gc/patch.stamp Makefile.am + ( cd gc && $(fix_config_guess_and_sub) && autoreconf ) + rm -rf gc-build + mkdir gc-build + (cd gc-build && $(srcdir)/gc/configure \ + CPPFLAGS="$(USER_CPPFLAGS)" \ + CFLAGS='$(USER_CFLAGS)' \ + LDFLAGS='$(USER_LDFLAGS)' \ + EXTRA_TEST_LIBS='$(USER_LDADD)' \ + --disable-shared --disable-threads \ + --disable-java-finalization --disable-gcj-support \ + --prefix=$(abs_builddir)/gc-install \ + --build=$(build_alias) --host=$(host_alias)) + touch $@ + +gc-build/build-stamp: gc-build/configure-stamp + cd gc-build && \ + make all gctest install + touch $@ + +libgc.a: gc-build/build-stamp + $(LN_S) -f gc-build/.libs/libgc.a . + +clean-local: + rm -rf gc-build + rm -rf gc-install + +CLEANFILES = include + +DISTCLEANFILES = $(srcdir)/$(gc_tarball) \ + gc-configure-stamp + diff --git a/benchmarks/boehm-gc/patches/01-gc-include-private-gcconfig-h.patch b/benchmarks/boehm-gc/patches/01-gc-include-private-gcconfig-h.patch new file mode 100644 index 0000000..9772e59 --- /dev/null +++ b/benchmarks/boehm-gc/patches/01-gc-include-private-gcconfig-h.patch @@ -0,0 +1,17 @@ +#! /bin/sh +patch -p1 -f $* < $0 +exit $? + +Tweak the configuration. + +--- gc/include/private/gcconfig.h~ 2007-06-29 02:00:09.000000000 +0200 ++++ gc/include/private/gcconfig.h 2008-02-21 17:08:20.000000000 +0100 +@@ -1275,7 +1275,7 @@ + extern int _end[]; + # define DATAEND ((ptr_t) (_end)) + /* # define MPROTECT_VDB Not quite working yet? */ +-# define DYNAMIC_LOADING ++# undef DYNAMIC_LOADING + # endif + # ifdef DARWIN + # define OS_TYPE "DARWIN" diff --git a/benchmarks/boehm-gc/patches/02-gc-mach_dep-c.patch b/benchmarks/boehm-gc/patches/02-gc-mach_dep-c.patch new file mode 100644 index 0000000..6c24087 --- /dev/null +++ b/benchmarks/boehm-gc/patches/02-gc-mach_dep-c.patch @@ -0,0 +1,18 @@ +#! /bin/sh +patch -p1 -f $* < $0 +exit $? + +Prefer use of setjmp to use of getcontext. + +--- gc/mach_dep.c~ 2007-07-02 19:07:21.000000000 +0200 ++++ gc/mach_dep.c 2008-02-29 15:13:39.000000000 +0100 +@@ -174,7 +174,7 @@ void GC_with_callee_saves_pushed(void (* + + # if defined(HAVE_PUSH_REGS) + GC_push_regs(); +-# elif defined(UNIX_LIKE) && !defined(DARWIN) && !defined(ARM32) ++# elif defined(UNIX_LIKE) && !defined(DARWIN) && !defined(ARM32) && !defined(HURD) + /* Older versions of Darwin seem to lack getcontext(). */ + /* ARM Linux often doesn't support a real getcontext(). */ + ucontext_t ctxt; + diff --git a/benchmarks/shared-memory-distribution.c b/benchmarks/shared-memory-distribution.c new file mode 100644 index 0000000..22a046a --- /dev/null +++ b/benchmarks/shared-memory-distribution.c @@ -0,0 +1,148 @@ +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/mman.h> +#include <errno.h> +#include <string.h> +#include <pthread.h> + +#include <hurd/activity.h> +#include <hurd/storage.h> +#include <hurd/startup.h> + +static addr_t activity; + +/* Initialized by the machine-specific startup-code. */ +extern struct hurd_startup_data *__hurd_startup_data; + +int +main (int argc, char *argv[]) +{ + extern int output_debug; + output_debug = 1; + + activity = __hurd_startup_data->activity; + +#define PAGES 1000 + + /* Allocate the buffer. */ + void *buffer = mmap (0, PAGESIZE * PAGES, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (buffer == MAP_FAILED) + { + printf ("Failed to allocate memory: %s\n", strerror (errno)); + return 1; + } + +#define THREADS 3 + /* And the activities. */ + addr_t activities[THREADS]; + + int i; + for (i = 0; i < THREADS; i ++) + activities[i] = storage_alloc (activity, cap_activity, + STORAGE_LONG_LIVED, + OBJECT_POLICY_DEFAULT, + ADDR_VOID).addr; + + bool terminate = false; + l4_thread_id_t tids[THREADS]; + for (i = 0; i < THREADS; i ++) + tids[i] = l4_nilthread; + + void *worker (void *arg) + { + int w = (intptr_t) arg; + + tids[w] = l4_myself (); + + pthread_setactivity_np (activities[w]); + + uintptr_t t = 0; + int count = 0; + while (! terminate) + { + uintptr_t *p = buffer + (rand () % PAGES) * PAGESIZE; + t = *p; + + count ++; + if (count % 100000 == 0) + debug (0, DEBUG_BOLD ("Read %d pages so far"), count); + + l4_thread_switch (tids[rand () % THREADS]); + } + + printf ("Thread %d: %d operations\n", w, count); + + /* We need to return t, otherwise, the above loop will be + optimized away. */ + return (void *) t; + } + + /* Start the threads. */ + pthread_t threads[THREADS]; + + error_t err; + for (i = 0; i < THREADS; i ++) + { + err = pthread_create (&threads[i], NULL, worker, (intptr_t) i); + if (err) + printf ("Failed to create thread: %s\n", strerror (errno)); + } + +#define ITERATIONS 100 + struct activity_stats stats[ITERATIONS][1 + THREADS]; + + uintptr_t next_period = 0; + for (i = 0; i < ITERATIONS; i ++) + { + debug (0, DEBUG_BOLD ("starting iteration %d (%x)"), i, l4_myself ()); + + int count; + struct activity_stats_buffer buffer; + + rm_activity_stats (activity, next_period, &buffer, &count); + assert (count > 0); + if (i != 0) + assert (buffer.stats[0].period != stats[i - 1][0].period); + + stats[i][0] = buffer.stats[0]; + + int j; + for (j = 0; j < THREADS; j ++) + { + rm_activity_stats (activities[j], next_period, &buffer, &count); + assert (count > 0); + stats[i][1 + j] = buffer.stats[0]; + } + + next_period = buffer.stats[0].period + 1; + } + + terminate = true; + for (i = 0; i < THREADS; i ++) + { + void *status; + pthread_join (threads[i], &status); + } + + printf ("parent "); + for (i = 0; i < THREADS; i ++) + printf (ADDR_FMT " ", ADDR_PRINTF (activities[i])); + printf ("\n"); + + for (i = 0; i < ITERATIONS; i ++) + { + int j; + + printf ("%d ", (int) stats[i][0].period); + + for (j = 0; j < 1 + THREADS; j ++) + printf ("%d ", (int) stats[i][j].clean + (int) stats[i][j].dirty); + printf ("\n"); + } + + printf ("Done!\n"); + + return 0; +} diff --git a/configure.ac b/configure.ac index 4a777b6..3897206 100644 --- a/configure.ac +++ b/configure.ac @@ -296,6 +296,8 @@ AC_CONFIG_FILES([Makefile newlib/Makefile hieronymus/Makefile ruth/Makefile + benchmarks/Makefile + benchmarks/boehm-gc/Makefile doc/Makefile ]) AC_OUTPUT |