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, 7 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Changes since 1.9: +1 -1 lines
Log Message:
whitespace

File Contents

# Content
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 //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 *
18 * 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 // Dimensions for test runs.
26 // 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 System.out.printf(" from %5d to %5d step %5d\n",
46 MIN_SIDE, MAX_SIDE, SIDE_STEP);
47 ForkJoinPool pool = new ForkJoinPool(procs);
48
49 boolean checked = false;
50 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 double nanosPerEdge = (double) elapsed / (4 * n);
60 System.out.printf(" %7.2f", nanosPerEdge);
61 if (!checked) {
62 checked = true;
63 checkSpanningTree(graph, root);
64 }
65 pool.invoke(new Resetter(graph, 0, graph.length));
66 }
67 graph = null;
68 System.out.println();
69 }
70 System.out.println(pool);
71 pool.shutdown();
72 }
73
74 static final class Node extends ForkJoinTask<Void> {
75 final Node[] neighbors;
76 Node parent;
77 Node next;
78
79 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 if (e != null &&
113 e.compareAndSetForkJoinTaskTag((short)0, (short)1)) {
114 e.parent = par;
115 e.next = newList;
116 newList = e;
117 if (batchSize == 0) {
118 int s = getQueuedTaskCount();
119 batchSize = ((s >= LOG_MAX_BATCH_SIZE) ?
120 (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 Driver(Node root) {
158 this.root = root;
159 }
160 public void compute() {
161 root.setForkJoinTaskTag((short)1);
162 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 for (int i = 0; i < sideLength; ++i) {
177 for (int j = 0; j < sideLength; ++j) {
178 Node[] a = vs[col + j].neighbors;
179 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 }
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
212 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 }