View Javadoc
1   //******************************************************************************
2   //
3   // File:    DynamicLongSchedule.java
4   // Package: edu.rit.pj
5   // Unit:    Class edu.rit.pj.DynamicLongSchedule
6   //
7   // This Java source file is copyright (C) 2009 by Alan Kaminsky. All rights
8   // reserved. For further information, contact the author, Alan Kaminsky, at
9   // ark@cs.rit.edu.
10  //
11  // This Java source file is part of the Parallel Java Library ("PJ"). PJ is free
12  // software; you can redistribute it and/or modify it under the terms of the GNU
13  // General Public License as published by the Free Software Foundation; either
14  // version 3 of the License, or (at your option) any later version.
15  //
16  // PJ is distributed in the hope that it will be useful, but WITHOUT ANY
17  // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
18  // A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19  //
20  // Linking this library statically or dynamically with other modules is making a
21  // combined work based on this library. Thus, the terms and conditions of the GNU
22  // General Public License cover the whole combination.
23  //
24  // As a special exception, the copyright holders of this library give you
25  // permission to link this library with independent modules to produce an
26  // executable, regardless of the license terms of these independent modules, and
27  // to copy and distribute the resulting executable under terms of your choice,
28  // provided that you also meet, for each linked independent module, the terms
29  // and conditions of the license of that module. An independent module is a module
30  // which is not derived from or based on this library. If you modify this library,
31  // you may extend this exception to your version of the library, but you are not
32  // obligated to do so. If you do not wish to do so, delete this exception
33  // statement from your version.
34  //
35  // A copy of the GNU General Public License is provided in the file gpl.txt. You
36  // may also obtain a copy of the GNU General Public License on the World Wide
37  // Web at http://www.gnu.org/licenses/gpl.html.
38  //
39  //******************************************************************************
40  package edu.rit.pj;
41  
42  import java.util.concurrent.atomic.AtomicLong;
43  
44  import edu.rit.util.LongRange;
45  
46  /**
47   * Class DynamicLongSchedule provides a dynamic schedule object. The loop index
48   * is type <code>long</code>. The loop iterations are apportioned into chunks of a
49   * given size (a given number of iterations per chunk). Each parallel team
50   * thread repeatedly performs the next available chunk of iterations until there
51   * are no more chunks. The final chunk may be smaller than the given chunk size.
52   *
53   * @author Alan Kaminsky
54   * @version 18-Nov-2009
55   */
56  class DynamicLongSchedule
57          extends LongSchedule {
58  
59  // Hidden data members.
60      // Loop iteration range.
61      private LongRange myLoopRange;
62  
63      // Number of iterations already handed out.
64      private AtomicLong N1 = new AtomicLong();
65  
66      // Chunk size.
67      private long N2;
68  
69  // Exported constructors.
70      /**
71       * Construct a new dynamic schedule object with a chunk size of 1.
72       */
73      public DynamicLongSchedule() {
74          this(1);
75      }
76  
77      /**
78       * Construct a new dynamic schedule object with the given chunk size.
79       *
80       * @param theChunkSize Chunk size.
81       * @exception IllegalArgumentException (unchecked exception) Thrown if
82       * <code>theChunkSize</code> is less than 1.
83       */
84      public DynamicLongSchedule(long theChunkSize) {
85          super();
86          if (theChunkSize < 1) {
87              throw new IllegalArgumentException("DynamicLongSchedule(): Chunk size = " + theChunkSize
88                      + " illegal");
89          }
90          N2 = theChunkSize;
91      }
92  
93      /**
94       * Construct a new dynamic schedule object. This constructor is for use by
95       * the <code>LongSchedule.parse()</code> method. <code>args</code> must be an array
96       * of one string, namely the chunk size, an integer &gt;= 1.
97       *
98       * @param args Array of argument strings.
99       * @exception IllegalArgumentException (unchecked exception) Thrown if
100      * <code>args</code> is not an array of one string. Thrown if the chunk size is
101      * less than 1.
102      */
103     public DynamicLongSchedule(String[] args) {
104         this(getChunkSize(args));
105     }
106 
107     private static long getChunkSize(String[] args) {
108         if (args.length != 1) {
109             throw new IllegalArgumentException("DynamicLongSchedule(): Usage: -Dpj.schedule=dynamic or -Dpj.schedule=\"dynamic(<n>)\"");
110         }
111         long theChunkSize;
112         try {
113             theChunkSize = Long.parseLong(args[0]);
114         } catch (NumberFormatException exc) {
115             throw new IllegalArgumentException("DynamicLongSchedule(): Chunk size = " + args[0]
116                     + " illegal");
117         }
118         return theChunkSize;
119     }
120 
121     /**
122      * Determine if this schedule is a fixed schedule. For a parallel team with
123      * <I>K</I> threads, a fixed schedule partitions the loop index range into
124      * exactly <I>K</I> chunks, one chunk for each thread, each chunk with
125      * predetermined upper and lower bounds.
126      *
127      * @return True if this is a fixed schedule, false otherwise.
128      */
129     public boolean isFixedSchedule() {
130         return false;
131     }
132 
133 // Hidden operations.
134     /**
135      * {@inheritDoc}
136      *
137      * Start generating chunks of iterations for a parallel for loop using this
138      * schedule.
139      * <P>
140      * The <code>start()</code> method is only called by a single thread in the
141      * Parallel Java middleware.
142      */
143     public void start(int K,
144             LongRange theLoopRange) {
145         myLoopRange = theLoopRange;
146         N1.set(0);
147     }
148 
149     /**
150      * {@inheritDoc}
151      *
152      * Obtain the next chunk of iterations for the given thread index. If there
153      * are more iterations, a range object is returned whose lower bound, upper
154      * bound, and stride specify the chunk of iterations to perform. The
155      * returned range object's stride is the same as that given to the
156      * <code>start()</code> method. The returned range object's lower bound and
157      * upper bound are contained within the range given to the <code>start()</code>
158      * method. If there are no more iterations, null is returned.
159      * <P>
160      * The <code>next()</code> method is called by multiple parallel team threads in
161      * the Parallel Java middleware. The <code>next()</code> method must be multiple
162      * thread safe.
163      */
164     public LongRange next(int theThreadIndex) {
165         for (;;) {
166             long oldN1 = N1.get();
167             LongRange result = myLoopRange.chunk(oldN1, N2);
168             long N = result.length();
169             if (N == 0) {
170                 return null;
171             }
172             long newN1 = oldN1 + N;
173             if (N1.compareAndSet(oldN1, newN1)) {
174                 return result;
175             }
176         }
177     }
178 
179 }