enable futures by default on Mac OS X and Linux x86/x86_64; future docs to ref and guide

svn: r18396
This commit is contained in:
Matthew Flatt 2010-02-28 22:06:59 +00:00
parent 2e0e4b8b95
commit e71bd71035
10 changed files with 74 additions and 185 deletions

View File

@ -1,164 +0,0 @@
#lang scribble/doc
@title{@bold{Futures}: Fine-grained Parallelism}
@; ----------------------------------------------------------------------
@(require scribble/manual
scribble/urls
scribble/struct
(for-label scheme
scheme/base
scheme/contract
scheme/future))
@; ----------------------------------------------------------------------
The PLT futures API enables the development of parallel programs which
take advantage of machines with multiple processors, cores, or
hardware threads.
@defmodule[scheme/future]{}
@defproc[(future [thunk (-> any)]) future?]{
Starts running @scheme[thunk] in parallel. The @scheme[future]
procedure returns immediately with a future descriptor value.
}
@defproc[(touch [f future?]) any]{
Returns the value computed in the future @scheme[f], blocking until
the future completes (if it has not already completed).
}
@defproc[(future? [x any/c]) boolean?]{
Returns @scheme[#t] if @scheme[x] is a future.
}
@defproc[(processor-count) exact-positive-integer?]{
Returns the number of processors/cores/hardware threads available on
the current system.
}
@section[#:tag "besteffortpar"]{Best-Effort Parallelism}
The @scheme[future] API represents a best-effort attempt to execute an
arbitrary segment of code in parallel. When designing programs and
algorithms which leverage @scheme[future] for parallel speedup, there
are a number of performance considerations to be aware of.
Futures are designed to accommodate the fact that many low-level
functions provided by the MzScheme virtual machine are not reentrant.
Thus, a future will execute its work in parallel until it detects an
attempt to perform an ``unsafe'' operation (e.g. invoking a
non-reentrant function). When such an operation is detected, the
future will block until @scheme[touch]ed, upon which the remainder of
its work will be done sequentially with respect to the touching
thread (in this case, ``thread'' refers to an OS thread).
To guarantee that unsafe operations never execute simultaneously, only
the initial OS thread used to start the MzScheme virtual machine (the
``runtime thread'') is allowed to execute them. If a parallel future
detects an attempted unsafe operation, it will signal the runtime
thread that pending unsafe work is available, then block, waiting for
the runtime thread to complete it. Note that as mentioned above, the
runtime thread will not attempt to do this work until the future is
explicitly touched. Also note that calls to @scheme[future] and
@scheme[touch] are themselves considered unsafe operations.
Consider the following contrived example:
@schemeblock[
(define (add-in-parallel a b)
(let ([f (future (lambda () (+ a b)))])
(touch f)))
(add-in-parallel 4 8)
]
The output of this program is, as expected:
@verbatim|{
12
}|
Now suppose we add a print message to our function for debugging purposes:
@schemeblock[
(define (add-in-parallel a b)
(let ([f (future
(lambda ()
(begin
(printf "Adding ~a and ~a together!~n" a b)
(+ a b))))])
(printf "About to touch my future...~n")
(touch f)))
(add-in-parallel 4 8)
]
Though this program still produces the same output, no work is being
done in parallel. Because @scheme[printf] is considered an unsafe
operation, f will block, and the print invocation (along with the
subsequent add) will not be performed until the @scheme[touch] call.
@section[#:tag "logging"]{How Do I Keep Those Cores Busy?}
It is not always obvious when or where unsafe operations may
be causing unacceptable performance degradation in parallel programs.
A a general guideline, any primitive that is inlined will run in parallel.
For example, fixnum and flonum addition do run in parallel,
but not bignum or rational addition. Similarly, vector operations are
generally safe, but not continuation operations. Also, allocation can run
in parallel, as long as only a little bit of allocation happens. Once a significant
amount of allocation happens, a parallel thread has to rendez-vous with the
runtime thread to get new, local memory.
To help tell what is happening in your program, the parallel threads
logs all of the points at which it has to synchronize
with the runtime thread.
For example, running the code in the previous
example in the debug log level produces the following output:
@verbatim|{
About to touch my future...
future: 0 waiting for runtime at 1259702453747.720947: printf
Adding 4 and 8 together!
12
}|
The message indicates which future blocked, the time it blocked and
the primitive operation that caused it to block.
To be sure we are not merely seeing the effects of a race condition in
this example, we can force the main thread to @scheme[sleep] for an
unreasonable amount of time:
@schemeblock[
(define (add-in-parallel a b)
(let ([f (future
(lambda ()
(begin
(printf "Adding ~a and ~a together!~n" a b)
(+ a b))))])
(sleep 10.0)
(printf "About to touch my future...~n")
(touch f)))
(add-in-parallel 4 8)
]
@verbatim|{
About to touch my future...
future: 0 waiting for runtime at 1259702453747.720947: printf
Adding 4 and 8 together!
12
}|
@section[#:tag "compiling"]{Enabling Futures in MzScheme Builds}
PLT's parallel-future support is only enabled if you pass
@DFlag{enable-futures} to @exec{configure} when you build PLT (and
that build currently only works with @exec{mzscheme}, not with
@exec{mred}). When parallel-future support is not enabled,
@scheme[future] just remembers the given thunk to call sequentially on
a later @scheme[touch].

View File

@ -1,3 +0,0 @@
#lang setup/infotab
(define scribblings '(("futures.scrbl" ())))

View File

@ -20,7 +20,7 @@ and memory performance of Scheme code.
@; ----------------------------------------------------------------------
@section{The Bytecode and Just-in-Time (JIT) Compilers}
@section[#:tag "JIT"]{The Bytecode and Just-in-Time (JIT) Compilers}
Every definition or expression to be evaluated by Scheme is compiled
to an internal bytecode format. In interactive mode, this compilation
@ -264,6 +264,9 @@ the generational garbage collector (described later in
reasonably cheap. Fixnums, in contrast are never boxed, so they are
typically cheap to use.
@margin-note{See @secref["effective-futures"] for an example use of
@tech{flonum}-specific operations.}
The @schememodname[scheme/flonum] library provides flonum-specific
operations, and combinations of flonum operations allow the @tech{JIT}
compiler to generate code that avoids boxing and unboxing intermediate
@ -361,3 +364,7 @@ then the expansion of the @scheme[let] form to implement
@scheme[m-loop] involves a closure over @scheme[n], but the compiler
automatically converts the closure to pass itself @scheme[n] as an
argument instead.
@; ----------------------------------------------------------------------
@include-section["futures.scrbl"]

View File

@ -5,7 +5,9 @@
PLT Scheme supports multiple threads of control within a program,
thread-local storage, some primitive synchronization mechanisms, and a
framework for composing synchronization abstractions.
framework for composing synchronization abstractions. In addition, the
@scheme[scheme/future] library provides some support for parallelism
to improve performance.
@local-table-of-contents[]
@ -14,5 +16,4 @@ framework for composing synchronization abstractions.
@include-section["threads.scrbl"]
@include-section["sync.scrbl"]
@include-section["thread-local.scrbl"]
@include-section["futures.scrbl"]

View File

@ -678,7 +678,8 @@ escape-continuation aborts can cross continuation barriers.
Scheme supports multiple @deftech{threads} of evaluation. Threads run
concurrently, in the sense that one thread can preempt another without
its cooperation, but threads currently all run on the same processor
(i.e., the same underlying OS process and thread).
(i.e., the same underlying OS process and thread). See also
@secref["futures"].
Threads are created explicitly by functions such as @scheme[thread].
In terms of the evaluation model, each step in evaluation actually consists of multiple concurrent

View File

@ -4,7 +4,7 @@
@title[#:tag "threads"]{Threads}
See @secref["thread-model"] for basic information on the PLT Scheme
thread model.
thread model. See also @secref["futures"].
When a thread is created, it is placed into the management of the
@tech{current custodian} and added to the current thread group (see

38
src/configure vendored
View File

@ -1349,7 +1349,7 @@ Optional Features:
--enable-jit compile JIT support (enabled by default)
--enable-foreign compile foreign support (enabled by default)
--enable-places compile places support
--enable-futures compile futures support
--enable-futures compile futures support (usually enabled by default)
--enable-cgcdefault use CGC (Boehm or Senora) as default build
--enable-sgc use Senora GC instead of the Boehm GC
--enable-sgcdebug use Senora GC for debugging
@ -5865,6 +5865,7 @@ case $OS in
case `$UNAME -m` in
#Required for CentOS 4.6
x86_64)
enable_futures_by_default=yes
CGC_X86_64="1"
if test -d /usr/X11R6/lib64 ; then
X_LIBS="$X_LIBS -L/usr/X11R6/lib64"
@ -5878,6 +5879,9 @@ case $OS in
alpha)
EXTRA_GMP_OBJ="gmp_alpha_gcc.o"
;;
i386,i486,i586,i686)
enable_futures_by_default=yes
;;
*)
;;
esac
@ -5931,6 +5935,8 @@ case $OS in
LDFLAGS="$LDFLAGS -isysroot ${enable_sdk} -mmacosx-version-min=10.4"
fi
enable_futures_by_default=yes
PREFLAGS="$PREFLAGS -DOS_X -D_DARWIN_UNLIMITED_SELECT"
STRIP_DEBUG="/usr/bin/strip -S"
@ -10705,28 +10711,50 @@ fi
if test "${enable_pthread}" = "yes" ; then
PREFLAGS="$PREFLAGS -D_THREAD_SAFE"
X_EXTRA_LIBS="$X_EXTRA_LIBS -pthread"
MZOPTIONS="$MZOPTIONS -DUSE_PTHREAD_INSTEAD_OF_ITIMER"
cat >>confdefs.h <<\_ACEOF
#define USE_PTHREAD_INSTEAD_OF_ITIMER 1
_ACEOF
fi
############### places ###################
if test "${enable_places}" = "yes" ; then
PREFLAGS="$PREFLAGS -DMZ_USE_PLACES"
cat >>confdefs.h <<\_ACEOF
#define MZ_USE_PLACES 1
_ACEOF
LDFLAGS="$LDFLAGS -pthread"
enable_mzrt=yes
fi
############### futures ###################
if test "${enable_futures_by_default}" = "yes" ; then
if test "${enable_futures}" = "" ; then
enable_futures=yes
fi
fi
if test "${enable_futures}" = "yes" ; then
PREFLAGS="$PREFLAGS -DMZ_USE_FUTURES"
cat >>confdefs.h <<\_ACEOF
#define MZ_USE_FUTURES 1
_ACEOF
enable_mzrt=yes
fi
############### OS threads ###################
if test "${enable_mzrt}" = "yes" ; then
PREFLAGS="$PREFLAGS -DUSE_PTHREAD_INSTEAD_OF_ITIMER"
cat >>confdefs.h <<\_ACEOF
#define USE_PTHREAD_INSTEAD_OF_ITIMER 1
_ACEOF
LDFLAGS="$LDFLAGS -pthread"
MZRT_CGC_FLAGS="$GC_THREADS_FLAG -DTHREAD_LOCAL_ALLOC"
LIBATOM="LIBATOM_USE"

View File

@ -44,7 +44,7 @@ AC_ARG_ENABLE(jit, [ --enable-jit compile JIT support (enabled b
AC_ARG_ENABLE(foreign, [ --enable-foreign compile foreign support (enabled by default)], , enable_foreign=yes)
AC_ARG_ENABLE(places, [ --enable-places compile places support])
AC_ARG_ENABLE(futures, [ --enable-futures compile futures support])
AC_ARG_ENABLE(futures, [ --enable-futures compile futures support (usually enabled by default)])
AC_ARG_ENABLE(cgcdefault, [ --enable-cgcdefault use CGC (Boehm or Senora) as default build])
AC_ARG_ENABLE(sgc, [ --enable-sgc use Senora GC instead of the Boehm GC])
@ -575,6 +575,7 @@ case $OS in
case `$UNAME -m` in
#Required for CentOS 4.6
x86_64)
enable_futures_by_default=yes
CGC_X86_64="1"
if test -d /usr/X11R6/lib64 ; then
X_LIBS="$X_LIBS -L/usr/X11R6/lib64"
@ -588,6 +589,9 @@ case $OS in
alpha)
EXTRA_GMP_OBJ="gmp_alpha_gcc.o"
;;
i386,i486,i586,i686)
enable_futures_by_default=yes
;;
*)
;;
esac
@ -641,6 +645,8 @@ case $OS in
LDFLAGS="$LDFLAGS -isysroot ${enable_sdk} -mmacosx-version-min=10.4"
fi
enable_futures_by_default=yes
PREFLAGS="$PREFLAGS -DOS_X -D_DARWIN_UNLIMITED_SELECT"
STRIP_DEBUG="/usr/bin/strip -S"
@ -1135,28 +1141,34 @@ fi
if test "${enable_pthread}" = "yes" ; then
PREFLAGS="$PREFLAGS -D_THREAD_SAFE"
X_EXTRA_LIBS="$X_EXTRA_LIBS -pthread"
MZOPTIONS="$MZOPTIONS -DUSE_PTHREAD_INSTEAD_OF_ITIMER"
AC_DEFINE(USE_PTHREAD_INSTEAD_OF_ITIMER, 1, [Pthread timer enabled])
fi
############### places ###################
if test "${enable_places}" = "yes" ; then
PREFLAGS="$PREFLAGS -DMZ_USE_PLACES"
AC_DEFINE(MZ_USE_PLACES,1,[Places enabled])
LDFLAGS="$LDFLAGS -pthread"
enable_mzrt=yes
fi
############### futures ###################
if test "${enable_futures_by_default}" = "yes" ; then
if test "${enable_futures}" = "" ; then
enable_futures=yes
fi
fi
if test "${enable_futures}" = "yes" ; then
PREFLAGS="$PREFLAGS -DMZ_USE_FUTURES"
AC_DEFINE(MZ_USE_FUTURES,1,[Futures enabled])
enable_mzrt=yes
fi
############### OS threads ###################
if test "${enable_mzrt}" = "yes" ; then
PREFLAGS="$PREFLAGS -DUSE_PTHREAD_INSTEAD_OF_ITIMER"
AC_DEFINE(USE_PTHREAD_INSTEAD_OF_ITIMER, 1, [Pthread timer enabled])
LDFLAGS="$LDFLAGS -pthread"
MZRT_CGC_FLAGS="$GC_THREADS_FLAG -DTHREAD_LOCAL_ALLOC"
LIBATOM="LIBATOM_USE"

View File

@ -35,4 +35,11 @@
/* Whether __attribute__ ((noinline)) works */
#undef MZ_USE_NOINLINE
/* Enable futures and/or places: */
#undef MZ_USE_FUTURES
#undef MZ_USE_PLACES
/* Configure use of pthreads for the user-thread timer: */
#undef USE_PTHREAD_INSTEAD_OF_ITIMER
#endif

View File

@ -13,12 +13,12 @@
consistently.)
*/
#define MZSCHEME_VERSION "4.2.4.4"
#define MZSCHEME_VERSION "4.2.4.5"
#define MZSCHEME_VERSION_X 4
#define MZSCHEME_VERSION_Y 2
#define MZSCHEME_VERSION_Z 4
#define MZSCHEME_VERSION_W 4
#define MZSCHEME_VERSION_W 5
#define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y)
#define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W)