ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/loops/TorusSpanningTree.java
Revision: 1.10
Committed: Sat Sep 12 20:57:12 2015 UTC (8 years, 8 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Changes since 1.9: +1 -1 lines
Log Message:
whitespace

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 jsr166 1.8 * http://creativecommons.org/publicdomain/zero/1.0/
5 dl 1.1 */
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 jsr166 1.7 System.out.printf(" %7.2f", nanosPerEdge);
61 dl 1.6 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 dl 1.9 graph = null;
68 dl 1.1 System.out.println();
69 jsr166 1.2 }
70 dl 1.6 System.out.println(pool);
71 jsr166 1.2 pool.shutdown();
72 dl 1.1 }
73    
74     static final class Node extends ForkJoinTask<Void> {
75 jsr166 1.2 final Node[] neighbors;
76 dl 1.1 Node parent;
77     Node next;
78 jsr166 1.2
79 dl 1.1 Node(Node[] nbrs) {
80     neighbors = nbrs;
81     parent = this;
82     }
83    
84     /*
85     * Traverse the list ("oldList") embedded across .next fields,
86     * starting at this node, placing newly discovered neighboring
87     * nodes in newList. If the oldList becomes exhausted, swap in
88     * newList and continue. Otherwise, whenever the length of
89     * newList exceeds current number of tasks in work-stealing
90     * queue, push list onto queue.
91     */
92    
93     static final int LOG_MAX_BATCH_SIZE = 7;
94    
95     /**
96     * Since tasks are never joined, we bypass Recursive{Action,Task}
97     * and just directly implement exec
98     */
99     public boolean exec() {
100     int batchSize = 0; // computed lazily
101     Node newList = null;
102     int newLength = 0;
103     Node oldList = this;
104     Node par = parent;
105     do {
106     Node v = oldList;
107     Node[] edges = v.neighbors;
108     oldList = v.next;
109     int nedges = edges.length;
110     for (int k = 0; k < nedges; ++k) {
111     Node e = edges[k];
112 jsr166 1.10 if (e != null &&
113 dl 1.9 e.compareAndSetForkJoinTaskTag((short)0, (short)1)) {
114 dl 1.1 e.parent = par;
115     e.next = newList;
116     newList = e;
117     if (batchSize == 0) {
118     int s = getQueuedTaskCount();
119 jsr166 1.3 batchSize = ((s >= LOG_MAX_BATCH_SIZE) ?
120 dl 1.1 (1 << LOG_MAX_BATCH_SIZE) :
121     (1 << s));
122     }
123     if (++newLength >= batchSize) {
124     newLength = 0;
125     batchSize = 0;
126     if (oldList == null)
127     oldList = newList;
128     else
129     newList.fork();
130     newList = null;
131     }
132     }
133     }
134     if (oldList == null) {
135     oldList = newList;
136     newList = null;
137     newLength = 0;
138     }
139     } while (oldList != null);
140     return false;
141     }
142    
143     // required abstract implementations for ForkJoinTask
144     public final Void getRawResult() { return null; }
145     protected final void setRawResult(Void mustBeNull) { }
146    
147     public void reset() {
148     reinitialize();
149     parent = this;
150     next = null;
151     }
152    
153     }
154    
155     static final class Driver extends RecursiveAction {
156     final Node root;
157 jsr166 1.2 Driver(Node root) {
158 dl 1.1 this.root = root;
159     }
160     public void compute() {
161 dl 1.9 root.setForkJoinTaskTag((short)1);
162 dl 1.1 root.fork();
163     helpQuiesce();
164     }
165     }
166    
167     static Node[] makeGraph(int sideLength) {
168     int n = sideLength * sideLength;
169     Node[] vs = new Node[n];
170     for (int i = 0; i < n; ++i)
171     vs[i] = new Node(new Node[4]);
172    
173     // connect each node to left, right, up, down neighbors
174     int maxcol = n - sideLength;
175     int col = 0;
176 jsr166 1.3 for (int i = 0; i < sideLength; ++i) {
177     for (int j = 0; j < sideLength; ++j) {
178 dl 1.1 Node[] a = vs[col + j].neighbors;
179 jsr166 1.3 a[0] = vs[col + ((j < sideLength-1) ? (j+1) : 0)];
180     a[1] = vs[col + ((j != 0) ? (j-1) : (sideLength-1))];
181     a[2] = vs[j + ((i < sideLength-1) ? (col + sideLength) : 0)];
182     a[3] = vs[j + ((i != 0) ? (col - sideLength) : maxcol)];
183 dl 1.1 }
184     col += sideLength;
185     }
186     return vs;
187     }
188    
189     static void resetAll(Node[] g) {
190     for (int i = 0; i < g.length; ++i)
191     g[i].reset();
192     }
193    
194     // check that all nodes have parents, and no cycles
195     static void checkSpanningTree(Node[] g, Node root) {
196     int n = g.length;
197     for (int i = 0; i < n; ++i) {
198     Node v = g[i];
199     Node p = v;
200     int k = n;
201     while (p != root) {
202     if (p == null)
203     throw new RuntimeException("null parent");
204     if (--k <= 0)
205     throw new RuntimeException("cycle");
206     p = p.parent;
207     }
208     v.parent = root;
209     }
210     }
211 jsr166 1.2
212 dl 1.6 static final class Resetter extends RecursiveAction {
213     final Node[] g;
214     final int lo, hi;
215     Resetter(Node[] g, int lo, int hi) {
216     this.g = g; this.lo = lo; this.hi = hi;
217     }
218     public void compute() {
219     int mid = (lo + hi) >>> 1;
220     if (mid == lo || getSurplusQueuedTaskCount() > 3) {
221     for (int i = lo; i < hi; ++i)
222     g[i].reset();
223     }
224     else
225     invokeAll(new Resetter(g, lo, mid), new Resetter(g, mid, hi));
226     }
227     }
228 dl 1.1 }