1 //******************************************************************************
2 //
3 // File: DynamicIntegerSchedule.java
4 // Package: edu.rit.pj
5 // Unit: Class edu.rit.pj.DynamicIntegerSchedule
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.AtomicInteger;
43
44 import edu.rit.util.Range;
45
46 /**
47 * Class DynamicIntegerSchedule provides a dynamic schedule object. The loop
48 * index is type <code>int</code>. The loop iterations are apportioned into chunks
49 * of a 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 17-Nov-2009
55 */
56 class DynamicIntegerSchedule
57 extends IntegerSchedule {
58
59 // Hidden data members.
60 // Loop iteration range.
61 private Range myLoopRange;
62
63 // Number of iterations already handed out.
64 private AtomicInteger N1 = new AtomicInteger();
65
66 // Chunk size.
67 private int N2;
68
69 // Exported constructors.
70 /**
71 * Construct a new dynamic schedule object with a chunk size of 1.
72 */
73 public DynamicIntegerSchedule() {
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 DynamicIntegerSchedule(int theChunkSize) {
85 super();
86 if (theChunkSize < 1) {
87 throw new IllegalArgumentException("DynamicIntegerSchedule(): 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>IntegerSchedule.parse()</code> method. <code>args</code> must be an
96 * array of one string, namely the chunk size, an integer >= 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 DynamicIntegerSchedule(String[] args) {
104 this(getChunkSize(args));
105 }
106
107 private static int getChunkSize(String[] args) {
108 if (args.length != 1) {
109 throw new IllegalArgumentException("DynamicIntegerSchedule(): Usage: -Dpj.schedule=dynamic or -Dpj.schedule=\"dynamic(<n>)\"");
110 }
111 int theChunkSize;
112 try {
113 theChunkSize = Integer.parseInt(args[0]);
114 } catch (NumberFormatException exc) {
115 throw new IllegalArgumentException("DynamicIntegerSchedule(): 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 Range 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 Range next(int theThreadIndex) {
165 for (;;) {
166 int oldN1 = N1.get();
167 Range result = myLoopRange.chunk(oldN1, N2);
168 int N = result.length();
169 if (N == 0) {
170 return null;
171 }
172 int newN1 = oldN1 + N;
173 if (N1.compareAndSet(oldN1, newN1)) {
174 return result;
175 }
176 }
177 }
178
179 }