ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/loops/TorusSpanningTree.java
Revision: 1.6
Committed: Sun Sep 19 12:55:37 2010 UTC (13 years, 8 months ago) by dl
Branch: MAIN
Changes since 1.5: +23 -3 lines
Log Message:
Add and update FJ and Queue tests

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/licenses/publicdomain
5     */
6    
7     //import jsr166y.*;
8     import java.util.*;
9     import java.util.concurrent.*;
10     import java.util.concurrent.atomic.*;
11    
12     /**
13     * This is reworked version of one of the tests reported on in the
14     * paper: Guojing Cong, Sreedhar Kodali, Sriram Krishnamoorty, Doug
15     * Lea, Vijay Saraswat and Tong Wen, "Solving irregular graph problems
16     * using adaptive work-stealing", ICPP, 2008.
17 jsr166 1.2 *
18 dl 1.1 * It runs the main batching algorithm discussed there for spanning
19     * trees, for a simple regular torus graph, where each node is
20     * connected to its left. right, up, and down neighbors.
21     */
22     public class TorusSpanningTree {
23     static final int NCPUS = Runtime.getRuntime().availableProcessors();
24    
25 jsr166 1.2 // Dimensions for test runs.
26 dl 1.1 // graphs have side*side nodes, each with 4 neighbors
27     static final int MIN_SIDE = 1000;
28     static final int MAX_SIDE = 3000;
29     static final int SIDE_STEP = 500;
30    
31     public static void main(String[] args) throws Exception {
32     Random rng = new Random();
33     int procs = NCPUS;
34     try {
35     if (args.length > 0)
36     procs = Integer.parseInt(args[0]);
37     }
38     catch (Exception e) {
39     System.out.println("Usage: java TorusSpanningTree <threads>");
40     return;
41     }
42     System.out.println("Number of threads: " + procs);
43     System.out.println("Printing nanosec per edge across replications");
44     System.out.print("for Toruses with side lengths");
45 jsr166 1.2 System.out.printf(" from %5d to %5d step %5d\n",
46 dl 1.1 MIN_SIDE, MAX_SIDE, SIDE_STEP);
47     ForkJoinPool pool = new ForkJoinPool(procs);
48    
49 dl 1.6 boolean checked = false;
50 dl 1.1 for (int side = MIN_SIDE; side <= MAX_SIDE; side += SIDE_STEP) {
51     int n = side * side;
52     Node[] graph = makeGraph(side);
53     System.out.printf( "N:%9d", n);
54     for (int j = 0; j < 8; ++j) {
55     Node root = graph[rng.nextInt(n)];
56     long start = System.nanoTime();
57     pool.invoke(new Driver(root));
58     long elapsed = System.nanoTime() - start;
59 jsr166 1.4 double nanosPerEdge = (double) elapsed / (4 * n);
60 dl 1.6 System.out.printf(" %7.2f", nanosPerEdge);
61     if (!checked) {
62     checked = true;
63 dl 1.1 checkSpanningTree(graph, root);
64 dl 1.6 }
65     pool.invoke(new Resetter(graph, 0, graph.length));
66 dl 1.1 }
67     System.out.println();
68 jsr166 1.2 }
69 dl 1.6 System.out.println(pool);
70 jsr166 1.2 pool.shutdown();
71 dl 1.1 }
72    
73     static final class Node extends ForkJoinTask<Void> {
74 jsr166 1.2 final Node[] neighbors;
75 dl 1.1 Node parent;
76     Node next;
77     volatile int mark;
78 jsr166 1.2
79 dl 1.1 Node(Node[] nbrs) {
80     neighbors = nbrs;
81     parent = this;
82     }
83    
84     static final AtomicIntegerFieldUpdater<Node> markUpdater =
85     AtomicIntegerFieldUpdater.newUpdater(Node.class, "mark");
86    
87     boolean tryMark() {
88     return mark == 0 && markUpdater.compareAndSet(this, 0, 1);
89     }
90     void setMark() { mark = 1; }
91    
92     /*
93     * Traverse the list ("oldList") embedded across .next fields,
94     * starting at this node, placing newly discovered neighboring
95     * nodes in newList. If the oldList becomes exhausted, swap in
96     * newList and continue. Otherwise, whenever the length of
97     * newList exceeds current number of tasks in work-stealing
98     * queue, push list onto queue.
99     */
100    
101     static final int LOG_MAX_BATCH_SIZE = 7;
102    
103     /**
104     * Since tasks are never joined, we bypass Recursive{Action,Task}
105     * and just directly implement exec
106     */
107     public boolean exec() {
108     int batchSize = 0; // computed lazily
109     Node newList = null;
110     int newLength = 0;
111     Node oldList = this;
112     Node par = parent;
113     do {
114     Node v = oldList;
115     Node[] edges = v.neighbors;
116     oldList = v.next;
117     int nedges = edges.length;
118     for (int k = 0; k < nedges; ++k) {
119     Node e = edges[k];
120     if (e != null && e.tryMark()) {
121     e.parent = par;
122     e.next = newList;
123     newList = e;
124     if (batchSize == 0) {
125     int s = getQueuedTaskCount();
126 jsr166 1.3 batchSize = ((s >= LOG_MAX_BATCH_SIZE) ?
127 dl 1.1 (1 << LOG_MAX_BATCH_SIZE) :
128     (1 << s));
129     }
130     if (++newLength >= batchSize) {
131     newLength = 0;
132     batchSize = 0;
133     if (oldList == null)
134     oldList = newList;
135     else
136     newList.fork();
137     newList = null;
138     }
139     }
140     }
141     if (oldList == null) {
142     oldList = newList;
143     newList = null;
144     newLength = 0;
145     }
146     } while (oldList != null);
147     return false;
148     }
149    
150     // required abstract implementations for ForkJoinTask
151     public final Void getRawResult() { return null; }
152     protected final void setRawResult(Void mustBeNull) { }
153    
154     public void reset() {
155     reinitialize();
156     parent = this;
157     next = null;
158     mark = 0;
159     }
160    
161     }
162    
163     static final class Driver extends RecursiveAction {
164     final Node root;
165 jsr166 1.2 Driver(Node root) {
166 dl 1.1 this.root = root;
167     }
168     public void compute() {
169     root.setMark();
170     root.fork();
171     helpQuiesce();
172     }
173     }
174    
175     static Node[] makeGraph(int sideLength) {
176     int n = sideLength * sideLength;
177     Node[] vs = new Node[n];
178     for (int i = 0; i < n; ++i)
179     vs[i] = new Node(new Node[4]);
180    
181     // connect each node to left, right, up, down neighbors
182     int maxcol = n - sideLength;
183     int col = 0;
184 jsr166 1.3 for (int i = 0; i < sideLength; ++i) {
185     for (int j = 0; j < sideLength; ++j) {
186 dl 1.1 Node[] a = vs[col + j].neighbors;
187 jsr166 1.3 a[0] = vs[col + ((j < sideLength-1) ? (j+1) : 0)];
188     a[1] = vs[col + ((j != 0) ? (j-1) : (sideLength-1))];
189     a[2] = vs[j + ((i < sideLength-1) ? (col + sideLength) : 0)];
190     a[3] = vs[j + ((i != 0) ? (col - sideLength) : maxcol)];
191 dl 1.1 }
192     col += sideLength;
193     }
194     return vs;
195     }
196    
197     static void resetAll(Node[] g) {
198     for (int i = 0; i < g.length; ++i)
199     g[i].reset();
200     }
201    
202     // check that all nodes have parents, and no cycles
203     static void checkSpanningTree(Node[] g, Node root) {
204     int n = g.length;
205     for (int i = 0; i < n; ++i) {
206     Node v = g[i];
207     Node p = v;
208     int k = n;
209     while (p != root) {
210     if (p == null)
211     throw new RuntimeException("null parent");
212     if (--k <= 0)
213     throw new RuntimeException("cycle");
214     p = p.parent;
215     }
216     v.parent = root;
217     }
218     }
219 jsr166 1.2
220 dl 1.6 static final class Resetter extends RecursiveAction {
221     final Node[] g;
222     final int lo, hi;
223     Resetter(Node[] g, int lo, int hi) {
224     this.g = g; this.lo = lo; this.hi = hi;
225     }
226     public void compute() {
227     int mid = (lo + hi) >>> 1;
228     if (mid == lo || getSurplusQueuedTaskCount() > 3) {
229     for (int i = lo; i < hi; ++i)
230     g[i].reset();
231     }
232     else
233     invokeAll(new Resetter(g, lo, mid), new Resetter(g, mid, hi));
234     }
235     }
236 dl 1.1 }