Thread View: comp.lang.functional
2 messages
2 total messages
Started by J. Michael Ashley
Tue, 17 Jul 1990 16:28
re: Id array comprehensions revisited
Author: J. Michael Ashley
Date: Tue, 17 Jul 1990 16:28
Date: Tue, 17 Jul 1990 16:28
62 lines
3286 bytes
3286 bytes
Wolfgand Grieskamp writes:
>In article <51123@iuvax.cs.indiana.edu> jashley@silver.ucs.indiana.edu (J. Michael Ashley) writes:
>>A little while ago I asked why array comprehensions are not parallel. In
>>particular, why does an array comprehension like this:
>>
>> { array (1, n) | [i] = f i || i <- 1 to n }
>>
>not evaluate the (f i)'s concurrently? Well, it turns out that the i's get
>generated sequentially as a list (a list in the data structure sense, mind
>you).
>
>This index list is intermediate and an optimizing compiler can eliminate it
>using loop fusion.
[ omitting the pleasantly detailed derivation of optimization ]
>Using the above rule you get finaly:
>
> DEF init1(A,f,i,n) == IF i>n THEN A
> IF i<=n THEN init1(update(A,i,f(i)),i+1,n) FI
>
>(A compiler will probably not use this fold/unfold method,
>because it depends to much on "eureka" steps. Furthermore, the view
>is based on the assumption that update is O(1). Such an update
>can be established by a sharing analysis for the given example).
>
>Regarding to concurrent initialization assume simplisticaly that init1
>is not strict in its first argument.
Actually, this is precisely the optimization that the current Id compiler
does right now; if it sees the construct "1 to n", then the compiler will
transform it into a loop.
Since we are using I-structures, the update is O(1) (without sharing analysis),
and init1 is not strict in it's first argument.
This doesn't solve the problem, however. Since we are using a dataflow
architecture, the function f will undergo partial evaluation to the point
where it must have it's argument. What this means is that if we have lots
and lots of processors, 90% of the work of creating the array is done by
the first iteration or two of init1. The execution is now bottlnecked by
this sequential generation of the indices.
A slightly better compiler will generate the indices in O(log n) time
without any trouble.
But this doesn't solve the problem completely. In the case of
accumulator comprehensions, the programmer will probably not be using this
easy-to-optimize "1 to n" construct. Instead, there will be some arbitrary
function (probably complicated) that *must return a list*. Even the most
trivial numerical codes will be more than a match for any compiler
optimization. So we are again stuck with lots of parallelism when
generating the elements of the list but bounded by an O(n) append to put
this results back together to form the final list.
Thomas Breuel suggested a couple of ways ("difference lists and/or pointer
jumping") to overcome the O(n) append problem. This is kind of a hack, and
Thomas admits that. I still sit on the position that lists are not the
right data structure for the indices.
mike ashley
jashley@lanl.gov
Re: Id array comprehensions revisited
Author: Wolfgang Grieskamp
Date: Tue, 17 Jul 1990 23:06
Date: Tue, 17 Jul 1990 23:06
50 lines
2992 bytes
2992 bytes
In article <51173@iuvax.cs.indiana.edu> jashley@silver.ucs.indiana.edu (J. Michael Ashley) writes: >Wolfgang Grieskamp writes: > >>Using the above rule you get finaly: >> >> DEF init1(A,f,i,n) == IF i>n THEN A >> IF i<=n THEN init1(update(A,i,f(i)),i+1,n) FI >> >> [...] >>Regarding to concurrent initialization assume simplisticaly that init1 >>is [[not strict]] lazy in its first argument. > > >This doesn't solve the problem, however. Since we are using a dataflow >architecture, the function f will undergo partial evaluation to the point >where it must have it's argument. If I get it right, this a specific problem of dataflow architectures. init1 fires only, when *all* arguments are available, so the next recursion level may only be reached when update(..) is available (must be something like this, I'am not so firm with dataflow architectures). Anyway, array initialization is not only in FORTRAN inherently parallel, but also in functional languages, and that should be pointed out. You might imagine the evaluation of init1 causes the creation of (n-i)+1 update "processes". The result of update is not required to bound the recursion, so init1 may terminate before any f(i) has been evaluated. The bottelneck appears, if some f(i) is ready, and update requires the updated array of the i+1 recursion level (this is a inherent problem (also in FORTRAN ...) you can only solve with some complicated analysis which ensures the commutativity of all performed updates). >In the case of >accumulator comprehensions, the programmer will probably not be using this >easy-to-optimize "1 to n" construct. Instead, there will be some arbitrary >function (probably complicated) that *must return a list*. Fusion in the case of the discussed array comprehensions works for *any* list producer with an arbitrary number of recursion and termination cases, not only for "1 to n". However, the (conceptual) fold step can be only applied to cases which have an outermost list constructor (so if you construct the index list with a concatenate of two sublists, it will fail for this case). Another problem is the compilers runtime ... so we actually need parallel machines to write nice compilers! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Wolfgang Grieskamp wg@opal.cs.tu-berlin.de tub!tubopal!wg wg%opal@DB0TUI11.BITNET
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads