ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/ArrayPrefixHelpers.java
Revision: 1.5
Committed: Sat Sep 19 18:36:55 2015 UTC (8 years, 7 months ago) by jsr166
Branch: MAIN
Changes since 1.4: +4 -60 lines
Log Message:
delete unused "Root task constructor"s

File Contents

# User Rev Content
1 dl 1.1 /*
2     * Written by Doug Lea with assistance from members of JCP JSR-166
3     * Expert Group and released to the public domain, as explained at
4     * http://creativecommons.org/publicdomain/zero/1.0/
5     */
6    
7     package java.util;
8 jsr166 1.4
9     import java.util.concurrent.CountedCompleter;
10 dl 1.1 import java.util.concurrent.ForkJoinPool;
11     import java.util.function.BinaryOperator;
12 jsr166 1.4 import java.util.function.DoubleBinaryOperator;
13 dl 1.1 import java.util.function.IntBinaryOperator;
14     import java.util.function.LongBinaryOperator;
15    
16     /**
17     * ForkJoin tasks to perform Arrays.parallelPrefix operations.
18     *
19     * @author Doug Lea
20     * @since 1.8
21     */
22     class ArrayPrefixHelpers {
23 jsr166 1.3 private ArrayPrefixHelpers() {} // non-instantiable
24 dl 1.1
25     /*
26     * Parallel prefix (aka cumulate, scan) task classes
27     * are based loosely on Guy Blelloch's original
28     * algorithm (http://www.cs.cmu.edu/~scandal/alg/scan.html):
29     * Keep dividing by two to threshold segment size, and then:
30     * Pass 1: Create tree of partial sums for each segment
31     * Pass 2: For each segment, cumulate with offset of left sibling
32     *
33     * This version improves performance within FJ framework mainly by
34     * allowing the second pass of ready left-hand sides to proceed
35     * even if some right-hand side first passes are still executing.
36     * It also combines first and second pass for leftmost segment,
37     * and skips the first pass for rightmost segment (whose result is
38     * not needed for second pass). It similarly manages to avoid
39     * requiring that users supply an identity basis for accumulations
40     * by tracking those segments/subtasks for which the first
41     * existing element is used as base.
42     *
43     * Managing this relies on ORing some bits in the pendingCount for
44     * phases/states: CUMULATE, SUMMED, and FINISHED. CUMULATE is the
45     * main phase bit. When false, segments compute only their sum.
46     * When true, they cumulate array elements. CUMULATE is set at
47     * root at beginning of second pass and then propagated down. But
48     * it may also be set earlier for subtrees with lo==0 (the left
49     * spine of tree). SUMMED is a one bit join count. For leafs, it
50     * is set when summed. For internal nodes, it becomes true when
51     * one child is summed. When the second child finishes summing,
52     * we then moves up tree to trigger the cumulate phase. FINISHED
53     * is also a one bit join count. For leafs, it is set when
54     * cumulated. For internal nodes, it becomes true when one child
55     * is cumulated. When the second child finishes cumulating, it
56     * then moves up tree, completing at the root.
57     *
58     * To better exploit locality and reduce overhead, the compute
59     * method loops starting with the current task, moving if possible
60     * to one of its subtasks rather than forking.
61     *
62     * As usual for this sort of utility, there are 4 versions, that
63     * are simple copy/paste/adapt variants of each other. (The
64     * double and int versions differ from long version solely by
65     * replacing "long" (with case-matching)).
66     */
67    
68     // see above
69     static final int CUMULATE = 1;
70     static final int SUMMED = 2;
71     static final int FINISHED = 4;
72    
73     /** The smallest subtask array partition size to use as threshold */
74     static final int MIN_PARTITION = 16;
75    
76     static final class CumulateTask<T> extends CountedCompleter<Void> {
77     final T[] array;
78     final BinaryOperator<T> function;
79     CumulateTask<T> left, right;
80     T in, out;
81     final int lo, hi, origin, fence, threshold;
82    
83     CumulateTask(CumulateTask<T> parent, BinaryOperator<T> function,
84     T[] array, int origin, int fence, int threshold,
85     int lo, int hi) {
86     super(parent);
87     this.function = function; this.array = array;
88     this.origin = origin; this.fence = fence;
89     this.threshold = threshold;
90     this.lo = lo; this.hi = hi;
91     }
92    
93     public final void compute() {
94     final BinaryOperator<T> fn;
95     final T[] a;
96     if ((fn = this.function) == null || (a = this.array) == null)
97     throw new NullPointerException(); // hoist checks
98     int th = threshold, org = origin, fnc = fence, l, h;
99     CumulateTask<T> t = this;
100     outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
101     if (h - l > th) {
102     CumulateTask<T> lt = t.left, rt = t.right, f;
103     if (lt == null) { // first pass
104     int mid = (l + h) >>> 1;
105     f = rt = t.right =
106     new CumulateTask<T>(t, fn, a, org, fnc, th, mid, h);
107     t = lt = t.left =
108     new CumulateTask<T>(t, fn, a, org, fnc, th, l, mid);
109     }
110     else { // possibly refork
111     T pin = t.in;
112     lt.in = pin;
113     f = t = null;
114     if (rt != null) {
115     T lout = lt.out;
116     rt.in = (l == org ? lout :
117     fn.apply(pin, lout));
118     for (int c;;) {
119     if (((c = rt.getPendingCount()) & CUMULATE) != 0)
120     break;
121     if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
122     t = rt;
123     break;
124     }
125     }
126     }
127     for (int c;;) {
128     if (((c = lt.getPendingCount()) & CUMULATE) != 0)
129     break;
130     if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
131     if (t != null)
132     f = t;
133     t = lt;
134     break;
135     }
136     }
137     if (t == null)
138     break;
139     }
140     if (f != null)
141     f.fork();
142     }
143     else {
144     int state; // Transition to sum, cumulate, or both
145     for (int b;;) {
146     if (((b = t.getPendingCount()) & FINISHED) != 0)
147     break outer; // already done
148     state = ((b & CUMULATE) != 0 ? FINISHED :
149     (l > org) ? SUMMED : (SUMMED|FINISHED));
150     if (t.compareAndSetPendingCount(b, b|state))
151     break;
152     }
153    
154     T sum;
155     if (state != SUMMED) {
156     int first;
157     if (l == org) { // leftmost; no in
158     sum = a[org];
159     first = org + 1;
160     }
161     else {
162     sum = t.in;
163     first = l;
164     }
165     for (int i = first; i < h; ++i) // cumulate
166     a[i] = sum = fn.apply(sum, a[i]);
167     }
168     else if (h < fnc) { // skip rightmost
169     sum = a[l];
170     for (int i = l + 1; i < h; ++i) // sum only
171     sum = fn.apply(sum, a[i]);
172     }
173     else
174     sum = t.in;
175     t.out = sum;
176     for (CumulateTask<T> par;;) { // propagate
177 jsr166 1.2 @SuppressWarnings("unchecked") CumulateTask<T> partmp
178     = (CumulateTask<T>)t.getCompleter();
179     if ((par = partmp) == null) {
180 dl 1.1 if ((state & FINISHED) != 0) // enable join
181     t.quietlyComplete();
182     break outer;
183     }
184     int b = par.getPendingCount();
185     if ((b & state & FINISHED) != 0)
186     t = par; // both done
187     else if ((b & state & SUMMED) != 0) { // both summed
188     int nextState; CumulateTask<T> lt, rt;
189     if ((lt = par.left) != null &&
190     (rt = par.right) != null) {
191     T lout = lt.out;
192     par.out = (rt.hi == fnc ? lout :
193     fn.apply(lout, rt.out));
194     }
195     int refork = (((b & CUMULATE) == 0 &&
196     par.lo == org) ? CUMULATE : 0);
197     if ((nextState = b|state|refork) == b ||
198     par.compareAndSetPendingCount(b, nextState)) {
199     state = SUMMED; // drop finished
200     t = par;
201     if (refork != 0)
202     par.fork();
203     }
204     }
205     else if (par.compareAndSetPendingCount(b, b|state))
206     break outer; // sib not ready
207     }
208     }
209     }
210     }
211     private static final long serialVersionUID = 5293554502939613543L;
212     }
213    
214     static final class LongCumulateTask extends CountedCompleter<Void> {
215     final long[] array;
216     final LongBinaryOperator function;
217     LongCumulateTask left, right;
218     long in, out;
219     final int lo, hi, origin, fence, threshold;
220    
221     LongCumulateTask(LongCumulateTask parent, LongBinaryOperator function,
222     long[] array, int origin, int fence, int threshold,
223     int lo, int hi) {
224     super(parent);
225     this.function = function; this.array = array;
226     this.origin = origin; this.fence = fence;
227     this.threshold = threshold;
228     this.lo = lo; this.hi = hi;
229     }
230    
231     public final void compute() {
232     final LongBinaryOperator fn;
233     final long[] a;
234     if ((fn = this.function) == null || (a = this.array) == null)
235     throw new NullPointerException(); // hoist checks
236     int th = threshold, org = origin, fnc = fence, l, h;
237     LongCumulateTask t = this;
238     outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
239     if (h - l > th) {
240     LongCumulateTask lt = t.left, rt = t.right, f;
241     if (lt == null) { // first pass
242     int mid = (l + h) >>> 1;
243     f = rt = t.right =
244     new LongCumulateTask(t, fn, a, org, fnc, th, mid, h);
245     t = lt = t.left =
246     new LongCumulateTask(t, fn, a, org, fnc, th, l, mid);
247     }
248     else { // possibly refork
249     long pin = t.in;
250     lt.in = pin;
251     f = t = null;
252     if (rt != null) {
253     long lout = lt.out;
254     rt.in = (l == org ? lout :
255     fn.applyAsLong(pin, lout));
256     for (int c;;) {
257     if (((c = rt.getPendingCount()) & CUMULATE) != 0)
258     break;
259     if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
260     t = rt;
261     break;
262     }
263     }
264     }
265     for (int c;;) {
266     if (((c = lt.getPendingCount()) & CUMULATE) != 0)
267     break;
268     if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
269     if (t != null)
270     f = t;
271     t = lt;
272     break;
273     }
274     }
275     if (t == null)
276     break;
277     }
278     if (f != null)
279     f.fork();
280     }
281     else {
282     int state; // Transition to sum, cumulate, or both
283     for (int b;;) {
284     if (((b = t.getPendingCount()) & FINISHED) != 0)
285     break outer; // already done
286     state = ((b & CUMULATE) != 0 ? FINISHED :
287     (l > org) ? SUMMED : (SUMMED|FINISHED));
288     if (t.compareAndSetPendingCount(b, b|state))
289     break;
290     }
291    
292     long sum;
293     if (state != SUMMED) {
294     int first;
295     if (l == org) { // leftmost; no in
296     sum = a[org];
297     first = org + 1;
298     }
299     else {
300     sum = t.in;
301     first = l;
302     }
303     for (int i = first; i < h; ++i) // cumulate
304     a[i] = sum = fn.applyAsLong(sum, a[i]);
305     }
306     else if (h < fnc) { // skip rightmost
307     sum = a[l];
308     for (int i = l + 1; i < h; ++i) // sum only
309     sum = fn.applyAsLong(sum, a[i]);
310     }
311     else
312     sum = t.in;
313     t.out = sum;
314     for (LongCumulateTask par;;) { // propagate
315     if ((par = (LongCumulateTask)t.getCompleter()) == null) {
316     if ((state & FINISHED) != 0) // enable join
317     t.quietlyComplete();
318     break outer;
319     }
320     int b = par.getPendingCount();
321     if ((b & state & FINISHED) != 0)
322     t = par; // both done
323     else if ((b & state & SUMMED) != 0) { // both summed
324     int nextState; LongCumulateTask lt, rt;
325     if ((lt = par.left) != null &&
326     (rt = par.right) != null) {
327     long lout = lt.out;
328     par.out = (rt.hi == fnc ? lout :
329     fn.applyAsLong(lout, rt.out));
330     }
331     int refork = (((b & CUMULATE) == 0 &&
332     par.lo == org) ? CUMULATE : 0);
333     if ((nextState = b|state|refork) == b ||
334     par.compareAndSetPendingCount(b, nextState)) {
335     state = SUMMED; // drop finished
336     t = par;
337     if (refork != 0)
338     par.fork();
339     }
340     }
341     else if (par.compareAndSetPendingCount(b, b|state))
342     break outer; // sib not ready
343     }
344     }
345     }
346     }
347     private static final long serialVersionUID = -5074099945909284273L;
348     }
349    
350     static final class DoubleCumulateTask extends CountedCompleter<Void> {
351     final double[] array;
352     final DoubleBinaryOperator function;
353     DoubleCumulateTask left, right;
354     double in, out;
355     final int lo, hi, origin, fence, threshold;
356    
357     DoubleCumulateTask(DoubleCumulateTask parent, DoubleBinaryOperator function,
358 jsr166 1.5 double[] array, int origin, int fence, int threshold,
359     int lo, int hi) {
360 dl 1.1 super(parent);
361     this.function = function; this.array = array;
362     this.origin = origin; this.fence = fence;
363     this.threshold = threshold;
364     this.lo = lo; this.hi = hi;
365     }
366    
367     public final void compute() {
368     final DoubleBinaryOperator fn;
369     final double[] a;
370     if ((fn = this.function) == null || (a = this.array) == null)
371     throw new NullPointerException(); // hoist checks
372     int th = threshold, org = origin, fnc = fence, l, h;
373     DoubleCumulateTask t = this;
374     outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
375     if (h - l > th) {
376     DoubleCumulateTask lt = t.left, rt = t.right, f;
377     if (lt == null) { // first pass
378     int mid = (l + h) >>> 1;
379     f = rt = t.right =
380     new DoubleCumulateTask(t, fn, a, org, fnc, th, mid, h);
381     t = lt = t.left =
382     new DoubleCumulateTask(t, fn, a, org, fnc, th, l, mid);
383     }
384     else { // possibly refork
385     double pin = t.in;
386     lt.in = pin;
387     f = t = null;
388     if (rt != null) {
389     double lout = lt.out;
390     rt.in = (l == org ? lout :
391     fn.applyAsDouble(pin, lout));
392     for (int c;;) {
393     if (((c = rt.getPendingCount()) & CUMULATE) != 0)
394     break;
395     if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
396     t = rt;
397     break;
398     }
399     }
400     }
401     for (int c;;) {
402     if (((c = lt.getPendingCount()) & CUMULATE) != 0)
403     break;
404     if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
405     if (t != null)
406     f = t;
407     t = lt;
408     break;
409     }
410     }
411     if (t == null)
412     break;
413     }
414     if (f != null)
415     f.fork();
416     }
417     else {
418     int state; // Transition to sum, cumulate, or both
419     for (int b;;) {
420     if (((b = t.getPendingCount()) & FINISHED) != 0)
421     break outer; // already done
422     state = ((b & CUMULATE) != 0 ? FINISHED :
423     (l > org) ? SUMMED : (SUMMED|FINISHED));
424     if (t.compareAndSetPendingCount(b, b|state))
425     break;
426     }
427    
428     double sum;
429     if (state != SUMMED) {
430     int first;
431     if (l == org) { // leftmost; no in
432     sum = a[org];
433     first = org + 1;
434     }
435     else {
436     sum = t.in;
437     first = l;
438     }
439     for (int i = first; i < h; ++i) // cumulate
440     a[i] = sum = fn.applyAsDouble(sum, a[i]);
441     }
442     else if (h < fnc) { // skip rightmost
443     sum = a[l];
444     for (int i = l + 1; i < h; ++i) // sum only
445     sum = fn.applyAsDouble(sum, a[i]);
446     }
447     else
448     sum = t.in;
449     t.out = sum;
450     for (DoubleCumulateTask par;;) { // propagate
451     if ((par = (DoubleCumulateTask)t.getCompleter()) == null) {
452     if ((state & FINISHED) != 0) // enable join
453     t.quietlyComplete();
454     break outer;
455     }
456     int b = par.getPendingCount();
457     if ((b & state & FINISHED) != 0)
458     t = par; // both done
459     else if ((b & state & SUMMED) != 0) { // both summed
460     int nextState; DoubleCumulateTask lt, rt;
461     if ((lt = par.left) != null &&
462     (rt = par.right) != null) {
463     double lout = lt.out;
464     par.out = (rt.hi == fnc ? lout :
465     fn.applyAsDouble(lout, rt.out));
466     }
467     int refork = (((b & CUMULATE) == 0 &&
468     par.lo == org) ? CUMULATE : 0);
469     if ((nextState = b|state|refork) == b ||
470     par.compareAndSetPendingCount(b, nextState)) {
471     state = SUMMED; // drop finished
472     t = par;
473     if (refork != 0)
474     par.fork();
475     }
476     }
477     else if (par.compareAndSetPendingCount(b, b|state))
478     break outer; // sib not ready
479     }
480     }
481     }
482     }
483     private static final long serialVersionUID = -586947823794232033L;
484     }
485    
486     static final class IntCumulateTask extends CountedCompleter<Void> {
487     final int[] array;
488     final IntBinaryOperator function;
489     IntCumulateTask left, right;
490     int in, out;
491     final int lo, hi, origin, fence, threshold;
492    
493     IntCumulateTask(IntCumulateTask parent, IntBinaryOperator function,
494 jsr166 1.5 int[] array, int origin, int fence, int threshold,
495     int lo, int hi) {
496 dl 1.1 super(parent);
497     this.function = function; this.array = array;
498     this.origin = origin; this.fence = fence;
499     this.threshold = threshold;
500     this.lo = lo; this.hi = hi;
501     }
502    
503     public final void compute() {
504     final IntBinaryOperator fn;
505     final int[] a;
506     if ((fn = this.function) == null || (a = this.array) == null)
507     throw new NullPointerException(); // hoist checks
508     int th = threshold, org = origin, fnc = fence, l, h;
509     IntCumulateTask t = this;
510     outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
511     if (h - l > th) {
512     IntCumulateTask lt = t.left, rt = t.right, f;
513     if (lt == null) { // first pass
514     int mid = (l + h) >>> 1;
515     f = rt = t.right =
516     new IntCumulateTask(t, fn, a, org, fnc, th, mid, h);
517     t = lt = t.left =
518     new IntCumulateTask(t, fn, a, org, fnc, th, l, mid);
519     }
520     else { // possibly refork
521     int pin = t.in;
522     lt.in = pin;
523     f = t = null;
524     if (rt != null) {
525     int lout = lt.out;
526     rt.in = (l == org ? lout :
527     fn.applyAsInt(pin, lout));
528     for (int c;;) {
529     if (((c = rt.getPendingCount()) & CUMULATE) != 0)
530     break;
531     if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
532     t = rt;
533     break;
534     }
535     }
536     }
537     for (int c;;) {
538     if (((c = lt.getPendingCount()) & CUMULATE) != 0)
539     break;
540     if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
541     if (t != null)
542     f = t;
543     t = lt;
544     break;
545     }
546     }
547     if (t == null)
548     break;
549     }
550     if (f != null)
551     f.fork();
552     }
553     else {
554     int state; // Transition to sum, cumulate, or both
555     for (int b;;) {
556     if (((b = t.getPendingCount()) & FINISHED) != 0)
557     break outer; // already done
558     state = ((b & CUMULATE) != 0 ? FINISHED :
559     (l > org) ? SUMMED : (SUMMED|FINISHED));
560     if (t.compareAndSetPendingCount(b, b|state))
561     break;
562     }
563    
564     int sum;
565     if (state != SUMMED) {
566     int first;
567     if (l == org) { // leftmost; no in
568     sum = a[org];
569     first = org + 1;
570     }
571     else {
572     sum = t.in;
573     first = l;
574     }
575     for (int i = first; i < h; ++i) // cumulate
576     a[i] = sum = fn.applyAsInt(sum, a[i]);
577     }
578     else if (h < fnc) { // skip rightmost
579     sum = a[l];
580     for (int i = l + 1; i < h; ++i) // sum only
581     sum = fn.applyAsInt(sum, a[i]);
582     }
583     else
584     sum = t.in;
585     t.out = sum;
586     for (IntCumulateTask par;;) { // propagate
587     if ((par = (IntCumulateTask)t.getCompleter()) == null) {
588     if ((state & FINISHED) != 0) // enable join
589     t.quietlyComplete();
590     break outer;
591     }
592     int b = par.getPendingCount();
593     if ((b & state & FINISHED) != 0)
594     t = par; // both done
595     else if ((b & state & SUMMED) != 0) { // both summed
596     int nextState; IntCumulateTask lt, rt;
597     if ((lt = par.left) != null &&
598     (rt = par.right) != null) {
599     int lout = lt.out;
600     par.out = (rt.hi == fnc ? lout :
601     fn.applyAsInt(lout, rt.out));
602     }
603     int refork = (((b & CUMULATE) == 0 &&
604     par.lo == org) ? CUMULATE : 0);
605     if ((nextState = b|state|refork) == b ||
606     par.compareAndSetPendingCount(b, nextState)) {
607     state = SUMMED; // drop finished
608     t = par;
609     if (refork != 0)
610     par.fork();
611     }
612     }
613     else if (par.compareAndSetPendingCount(b, b|state))
614     break outer; // sib not ready
615     }
616     }
617     }
618     }
619     private static final long serialVersionUID = 3731755594596840961L;
620     }
621    
622     }