001 /*
002 Galois, a framework to exploit amorphous data-parallelism in irregular
003 programs.
004
005 Copyright (C) 2010, The University of Texas at Austin. All rights reserved.
006 UNIVERSITY EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES CONCERNING THIS SOFTWARE
007 AND DOCUMENTATION, INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR ANY
008 PARTICULAR PURPOSE, NON-INFRINGEMENT AND WARRANTIES OF PERFORMANCE, AND ANY
009 WARRANTY THAT MIGHT OTHERWISE ARISE FROM COURSE OF DEALING OR USAGE OF TRADE.
010 NO WARRANTY IS EITHER EXPRESS OR IMPLIED WITH RESPECT TO THE USE OF THE
011 SOFTWARE OR DOCUMENTATION. Under no circumstances shall University be liable
012 for incidental, special, indirect, direct or consequential damages or loss of
013 profits, interruption of business, or related expenses which may arise from use
014 of Software or Documentation, including but not limited to those resulting from
015 defects in Software and/or Documentation, or loss or inaccuracy of data of any
016 kind.
017
018
019 */
020
021 package galois.runtime;
022
023 import galois.objects.Mappable;
024 import galois.objects.MethodFlag;
025 import galois.runtime.wl.OrderableWorklist;
026 import galois.runtime.wl.ParameterOrderedWorklist;
027 import galois.runtime.wl.ParameterUnorderedWorklist;
028 import galois.runtime.wl.ParameterWorklist;
029 import galois.runtime.wl.Priority;
030 import galois.runtime.wl.Worklist;
031 import galois.runtime.wl.Priority.Rule;
032
033 import java.io.FileInputStream;
034 import java.io.PrintStream;
035 import java.util.ArrayDeque;
036 import java.util.ArrayList;
037 import java.util.Arrays;
038 import java.util.HashMap;
039 import java.util.List;
040 import java.util.Map;
041 import java.util.Properties;
042 import java.util.concurrent.Callable;
043 import java.util.concurrent.ExecutionException;
044 import java.util.concurrent.atomic.AtomicInteger;
045 import java.util.concurrent.locks.Condition;
046 import java.util.concurrent.locks.ReentrantLock;
047 import java.util.logging.Level;
048 import java.util.logging.Logger;
049
050 import util.Launcher;
051 import util.Reflection;
052 import util.RuntimeStatistics;
053 import util.Sampler;
054 import util.StackSampler;
055 import util.Statistics;
056 import util.SystemProperties;
057 import util.fn.Lambda2Void;
058 import util.fn.Lambda3Void;
059 import util.fn.LambdaVoid;
060
061 /**
062 * Provides methods to access Galois runtime from application code.
063 *
064 */
065 public final class GaloisRuntime {
066 private static Logger logger = Logger.getLogger("galois.runtime.GaloisRuntime");
067
068 private static final int ITERATION_MULTIPLIER = SystemProperties.getIntProperty("iterationMultiplier", 1);
069 private static GaloisRuntime instance = null;
070
071 private boolean invalid;
072 private final boolean useParameter;
073 private final boolean useSerial;
074 private final ReplayFeature.Type replayType;
075 private final int maxThreads;
076
077 private final int maxIterations;
078 private final boolean moreStats;
079 private final boolean ignoreUserFlags;
080
081 private final ThreadSuspender threadSuspender;
082 private final ArrayDeque<ExecutorFrame> stack;
083 private final Executor root;
084 private ExecutorFrame current;
085 private static byte currentMask;
086
087 private GaloisRuntime(int numThreads, boolean useParameter, boolean useSerial, ReplayFeature.Type replayType,
088 boolean moreStats, boolean ignoreUserFlags) {
089 this.maxIterations = ITERATION_MULTIPLIER * numThreads;
090 this.maxThreads = useParameter ? 1 : numThreads;
091 this.useParameter = useParameter;
092 this.useSerial = useSerial;
093 this.replayType = replayType;
094 this.moreStats = moreStats;
095 this.ignoreUserFlags = ignoreUserFlags;
096
097 threadSuspender = new ThreadSuspender(maxThreads);
098 stack = new ArrayDeque<ExecutorFrame>();
099 root = new DummyExecutor();
100 current = new ExecutorFrame(new ThreadPool(numThreads), root, MethodFlag.NONE);
101 currentMask = current.mask;
102 }
103
104 /**
105 * Called by the testing framework to reset the runtime.
106 */
107 private static void initialize(int numThreads, boolean useParameter, boolean useSerial,
108 ReplayFeature.Type replayType, boolean moreStats, boolean ignoreUserFlags) {
109 if (instance != null) {
110 instance.invalidate();
111 }
112
113 instance = new GaloisRuntime(numThreads, useParameter, useSerial, replayType, moreStats, ignoreUserFlags);
114 }
115
116 /**
117 * Returns the current instance of the runtime.
118 *
119 * @return a reference to the current runtime
120 */
121 public static GaloisRuntime getRuntime() {
122 if (instance == null) {
123 // Use default serial Runtime
124 initialize(1, false, true, ReplayFeature.Type.NO, false, false);
125 }
126 return instance;
127 }
128
129 /**
130 * Creates an unordered Galois iterator that concurrently applies a function over all elements
131 * in some initial collection. Additional elements may be added during iteration.
132 *
133 * @param <T> type of elements to iterate over
134 * @param initial initial elements to iterate over
135 * @param body function to apply
136 * @param priority specification of the order elements are processed
137 * @throws ExecutionException if there is an uncaught exception during execution
138 * @see #foreach(Mappable, LambdaVoid)
139 * @see #foreach(Mappable, Lambda2Void, galois.runtime.wl.Priority.Rule)
140 */
141 public static <T> void foreach(Iterable<T> initial, Lambda2Void<T, ForeachContext<T>> body, Rule priority)
142 throws ExecutionException {
143 getRuntime().runBody(initial, body, priority);
144 }
145
146 /**
147 * Creates an unordered Galois iterator that concurrently applies a function over all elements
148 * in some initial collection. Additional elements may be added during iteration.
149 *
150 * @param <T> type of elements to iterate over
151 * @param initial initial elements to iterate over
152 * @param body function to apply
153 * @param priority specification of the order elements are processed
154 * @throws ExecutionException if there is an uncaught exception during execution
155 * @see #foreach(Mappable, LambdaVoid)
156 * @see #foreach(Iterable, Lambda2Void, galois.runtime.wl.Priority.Rule)
157 */
158 public static <T> void foreach(Mappable<T> initial, Lambda2Void<T, ForeachContext<T>> body, Rule priority)
159 throws ExecutionException {
160 getRuntime().runBody(initial, body, priority);
161 }
162
163 /**
164 * Creates an ordered Galois iterator that concurrently applies a function over all elements
165 * in some initial collection. Additional elements may be added during iteration. Elements
166 * are processed strictly according to some order.
167 *
168 * @param <T> type of elements to iterate over
169 * @param initial initial elements to iterate over
170 * @param body function to apply
171 * @param priority specification of the order elements are processed
172 * @throws ExecutionException if there is an uncaught exception during execution
173 * @see #foreachOrdered(Mappable, Lambda2Void, galois.runtime.wl.Priority.Rule)
174 */
175 public static <T> void foreachOrdered(Iterable<T> initial, Lambda2Void<T, ForeachContext<T>> body, Rule priority)
176 throws ExecutionException {
177 getRuntime().runOrderedBody(initial, body, priority);
178 }
179
180 /**
181 * Creates an ordered Galois iterator that concurrently applies a function over all elements
182 * in some initial collection. Additional elements may be added during iteration. Elements
183 * are processed strictly according to some order.
184 *
185 * @param <T> type of elements to iterate over
186 * @param initial initial elements to iterate over
187 * @param body function to apply
188 * @param priority specification of the order elements are processed
189 * @throws ExecutionException if there is an uncaught exception during execution
190 * @see #foreachOrdered(Iterable, Lambda2Void, galois.runtime.wl.Priority.Rule)
191 */
192 public static <T> void foreachOrdered(Mappable<T> initial, Lambda2Void<T, ForeachContext<T>> body, Rule priority)
193 throws ExecutionException {
194 getRuntime().runOrderedBody(initial, body, priority);
195 }
196
197 /**
198 * Creates an unordered Galois iterator that concurrently applies a function over all elements
199 * in some initial collection. In contrast to
200 * {@link #foreach(Mappable, Lambda2Void, galois.runtime.wl.Priority.Rule)},
201 * no additional elements may be added during iteration and the particular order
202 * elements are processed in is dictated by the particular {@link Mappable} instance.
203 *
204 * @param <T> type of elements to iterate over
205 * @param initial initial elements to iterate over
206 * @param body function to apply
207 * @throws ExecutionException if there is an uncaught exception during execution
208 * @see #foreach(Mappable, Lambda2Void, Object)
209 * @see #foreach(Mappable, Lambda3Void, Object, Object)
210 */
211 public static <T> void foreach(Mappable<T> initial, LambdaVoid<T> body) throws ExecutionException {
212 getRuntime().runBody(initial, body);
213 }
214
215 /**
216 * Creates an unordered Galois iterator that concurrently applies a function over all elements
217 * in some initial collection. In contrast to
218 * {@link #foreach(Mappable, Lambda2Void,galois.runtime.wl.Priority.Rule)},
219 * no additional elements may be added during iteration and the particular order
220 * elements are processed in is dictated by the particular {@link Mappable} instance.
221 *
222 * @param <T> type of elements to iterate over
223 * @param initial initial elements to iterate over
224 * @param body function to apply
225 * @param arg1 additional argument to function
226 * @throws ExecutionException if there is an uncaught exception during execution
227 * @see #foreach(Mappable, LambdaVoid)
228 * @see #foreach(Mappable, Lambda3Void, Object, Object)
229 */
230 public static <T, A1> void foreach(Mappable<T> initial, Lambda2Void<T, A1> body, A1 arg1) throws ExecutionException {
231 getRuntime().runBody(initial, body, arg1);
232 }
233
234 /**
235 * Creates an unordered Galois iterator that concurrently applies a function over all elements
236 * in some initial collection. In contrast to
237 * {@link #foreach(Mappable, Lambda2Void, galois.runtime.wl.Priority.Rule)},
238 * no additional elements may be added during iteration and the particular order
239 * elements are processed in is dictated by the particular {@link Mappable} instance.
240 *
241 * @param <T> type of elements to iterate over
242 * @param initial initial elements to iterate over
243 * @param body function to apply
244 * @param arg1 additional argument to function
245 * @param arg2 additional argument to function
246 * @throws ExecutionException if there is an uncaught exception during execution
247 * @see #foreach(Mappable, LambdaVoid)
248 * @see #foreach(Mappable, Lambda2Void, Object)
249 */
250 public static <T, A1, A2> void foreach(Mappable<T> initial, Lambda3Void<T, A1, A2> body, A1 arg1, A2 arg2)
251 throws ExecutionException {
252 getRuntime().runBody(initial, body, arg1, arg2);
253 }
254
255 private void invalidate() {
256 assert stack.isEmpty();
257 current.pool.shutdown();
258 invalid = true;
259 }
260
261 private void checkValidity() {
262 assert !invalid;
263 }
264
265 public void onCommit(Iteration it, Callback action) {
266 checkValidity();
267 current.executor.onCommit(it, action);
268 }
269
270 public void onUndo(Iteration it, Callback action) {
271 checkValidity();
272 current.executor.onUndo(it, action);
273 }
274
275 public void onRelease(Iteration it, ReleaseCallback action) {
276 checkValidity();
277 current.executor.onRelease(it, action);
278 }
279
280 public static boolean needMethodFlag(byte flags, byte option) {
281 // Since this is called very often, skip the validity check
282 // checkValidity();
283
284 // Apparently the following check even when converted to using static
285 // fields is slow
286 // if (useParameter)
287 // flags = MethodFlag.ALL;
288
289 return ((flags & currentMask) & option) != 0;
290 }
291
292 <T> void callAll(List<? extends Callable<T>> callables) throws InterruptedException, ExecutionException {
293 checkValidity();
294 current.pool.callAll(callables);
295 }
296
297 /**
298 * Gets the maximum number of threads that can be used by the Runtime.
299 *
300 * @return maximum number of threads available
301 */
302 public int getMaxThreads() {
303 checkValidity();
304 return maxThreads;
305 }
306
307 public int getMaxIterations() {
308 checkValidity();
309 return maxIterations;
310 }
311
312 /**
313 * Signals that conflict has been detected by the user/library code.
314 *
315 * @param it the current iteration
316 * @param conflicter the iteration that is in conflict with the current iteration
317 */
318 public void raiseConflict(Iteration it, Iteration conflicter) {
319 checkValidity();
320 current.executor.arbitrate(it, conflicter);
321 }
322
323 private void push(ExecutorFrame frame) {
324 stack.push(current);
325 current = frame;
326 currentMask = current.mask;
327 }
328
329 private void pop() {
330 current = stack.pop();
331 currentMask = current.mask;
332 }
333
334 void replaceWithRootContextAndCall(final Callback callback) throws ExecutionException {
335 ExecutorFrame oldFrame = current;
336
337 pop();
338 try {
339 pushContextAndCall(root, new Callable<IterationStatistics>() {
340 @Override
341 public IterationStatistics call() throws Exception {
342 callback.call();
343 return null;
344 }
345 });
346 } finally {
347 push(oldFrame);
348 }
349 }
350
351 private IterationStatistics __stackSamplerRecordMe(Callable<IterationStatistics> callback) throws Exception {
352 return callback.call();
353 }
354
355 private IterationStatistics pushContextAndCall(Executor executor, Callable<IterationStatistics> callback)
356 throws ExecutionException {
357 boolean suspended = false;
358 if (!current.executor.isSerial()) {
359 try {
360 // TODO(ddn): Can lead to deadlock (infinite livelock) when using mappable
361 // iterators because one thread sleeps holding its locks and the other threads
362 // keep executing but they can never suspend their executor
363 if (current.executor instanceof MappableExecutor)
364 throw new Error("Not yet supported");
365 threadSuspender.suspend(current.executor);
366 suspended = true;
367 } catch (InterruptedException e) {
368 throw new ExecutionException(e);
369 }
370 }
371
372 boolean isSerial = executor.isSerial();
373 byte mask = isSerial ? MethodFlag.NONE : MethodFlag.ALL;
374 // Try to reuse thread pool if possible
375 ThreadPool pool;
376 if (suspended) {
377 pool = new ThreadPool(maxThreads);
378 } else {
379 pool = current.pool;
380 }
381
382 push(new ExecutorFrame(pool, executor, mask));
383 try {
384 if (isSerial)
385 return __stackSamplerRecordMe(callback);
386 else
387 return callback.call();
388 } catch (Exception e) {
389 throw new ExecutionException(e);
390 } finally {
391 // Shutdown newly created thread pools
392 if (pool != null && suspended)
393 pool.shutdown();
394 pop();
395 }
396 }
397
398 private <T> void initializeWorklist(final Worklist<T> wl, Iterable<T> initial, Mappable<T> mappable)
399 throws ExecutionException {
400 final ForeachContext<T> ctx = new SimpleContext<T>(maxThreads);
401
402 if (initial != null) {
403 for (T item : initial) {
404 wl.addInitial(item, ctx);
405 }
406 } else {
407 mappable.map(new LambdaVoid<T>() {
408 @Override
409 public void call(T item) {
410 wl.addInitial(item, ctx);
411 }
412 });
413 }
414 wl.finishAddInitial();
415 }
416
417 private <T, S> void initializeWorklist(final ParameterWorklist<T, S> wl, Iterable<T> initial, Mappable<T> mappable)
418 throws ExecutionException {
419 if (initial != null) {
420 for (T item : initial) {
421 wl.add(item);
422 }
423 } else {
424 mappable.map(new LambdaVoid<T>() {
425 @Override
426 public void call(T item) {
427 wl.add(item);
428 }
429 });
430 }
431 }
432
433 private <T> void runBody(Mappable<T> mappable, Lambda2Void<T, ForeachContext<T>> body, Rule priority)
434 throws ExecutionException {
435 checkValidity();
436 runBody(null, mappable, body, ExecutorType.UNORDERED, priority);
437 }
438
439 private <T> void runBody(Iterable<T> initial, Lambda2Void<T, ForeachContext<T>> body, Rule priority)
440 throws ExecutionException {
441 checkValidity();
442 runBody(initial, null, body, ExecutorType.UNORDERED, priority);
443 }
444
445 private <T> void runOrderedBody(Mappable<T> mappable, Lambda2Void<T, ForeachContext<T>> body, Rule priority)
446 throws ExecutionException {
447 checkValidity();
448 runBody(null, mappable, body, ExecutorType.ORDERED, priority);
449 }
450
451 private <T> void runOrderedBody(Iterable<T> initial, Lambda2Void<T, ForeachContext<T>> body, Rule priority)
452 throws ExecutionException {
453 checkValidity();
454 runBody(initial, null, body, ExecutorType.ORDERED, priority);
455 }
456
457 @SuppressWarnings("unchecked")
458 private <T> void runBody(Iterable<T> initial, Mappable<T> mappable, final Lambda2Void<T, ForeachContext<T>> body,
459 ExecutorType type, Rule priority) throws ExecutionException {
460
461 IterationStatistics stats = null;
462 if (replayType == ReplayFeature.Type.PLAYBACK) {
463 final Worklist<T> wl = Priority.makeSerial(priority);
464 final PlaybackReplayFeature<T> feature = (PlaybackReplayFeature<T>) Features.getReplayFeature();
465 initializeWorklist(wl, initial, mappable);
466 stats = pushContextAndCall(feature, new Callable<IterationStatistics>() {
467 @Override
468 public IterationStatistics call() throws Exception {
469 return feature.call(body, wl);
470 }
471 });
472 } else if (useSerial) {
473 final Worklist<T> wl = Priority.makeSerial(priority);
474 final SerialExecutor<T> ex = new SerialExecutor<T>();
475 initializeWorklist(wl, initial, mappable);
476 stats = pushContextAndCall(ex, new Callable<IterationStatistics>() {
477 @Override
478 public IterationStatistics call() throws Exception {
479 return ex.call(body, wl);
480 }
481 });
482 } else if (useParameter) {
483 if (type == ExecutorType.ORDERED) {
484 final ParameterOrderedWorklist<T> wl = Priority.makeParameterOrdered(priority);
485 final ParameterOrderedExecutor<T> ex = new ParameterOrderedExecutor<T>(wl);
486 initializeWorklist(wl, initial, mappable);
487 stats = pushContextAndCall(ex, new Callable<IterationStatistics>() {
488 @Override
489 public IterationStatistics call() throws Exception {
490 return ex.call(body);
491 }
492 });
493 } else {
494 assert type == ExecutorType.BAREBONES || type == ExecutorType.UNORDERED;
495 final ParameterUnorderedWorklist<T> wl = Priority.makeParameterUnordered();
496 final AbstractParameterExecutor<T, T> ex = new ParameterUnorderedExecutor<T>(wl);
497 initializeWorklist(wl, initial, mappable);
498 stats = pushContextAndCall(ex, new Callable<IterationStatistics>() {
499 @Override
500 public IterationStatistics call() throws Exception {
501 return ex.call(body);
502 }
503 });
504 }
505 } else {
506 if (type == ExecutorType.ORDERED) {
507 final OrderableWorklist<T> wl = Priority.makeOrdered(priority);
508 final OrderedExecutor<T> ex = new OrderedExecutor<T>(wl);
509 initializeWorklist(wl, initial, mappable);
510 stats = pushContextAndCall(ex, new Callable<IterationStatistics>() {
511 @Override
512 public IterationStatistics call() throws Exception {
513 return ex.call(body, wl);
514 }
515 });
516 } else if (type == ExecutorType.BAREBONES) {
517 final Worklist<T> wl = Priority.makeUnordered(priority);
518 final BarebonesExecutor<T> ex = new BarebonesExecutor<T>();
519 initializeWorklist(wl, initial, mappable);
520 stats = pushContextAndCall(ex, new Callable<IterationStatistics>() {
521 @Override
522 public IterationStatistics call() throws Exception {
523 return ex.call(body, wl);
524 }
525 });
526 } else {
527 assert type == ExecutorType.UNORDERED;
528 final Worklist<T> wl = Priority.makeUnordered(priority);
529 final UnorderedExecutor<T> ex = new UnorderedExecutor<T>();
530 initializeWorklist(wl, initial, mappable);
531 stats = pushContextAndCall(ex, new Callable<IterationStatistics>() {
532 @Override
533 public IterationStatistics call() throws Exception {
534 return ex.call(body, wl);
535 }
536 });
537 }
538 }
539 if (stats == null)
540 throw new Error("unknown executor");
541
542 Launcher.getLauncher().addStats(stats);
543 Features.getReplayFeature().onFinish();
544 }
545
546 @SuppressWarnings("unchecked")
547 private <T> void runBody(final Mappable<T> mappable, final Object body, final MappableType type, final Object... args)
548 throws ExecutionException {
549 IterationStatistics stats = null;
550
551 if (replayType == ReplayFeature.Type.PLAYBACK) {
552 final PlaybackReplayFeature<T> feature = (PlaybackReplayFeature<T>) Features.getReplayFeature();
553 stats = pushContextAndCall(feature, new Callable<IterationStatistics>() {
554 @Override
555 public IterationStatistics call() throws Exception {
556 return feature.call(mappable, body, type, args);
557 }
558 });
559 } else if (useSerial) {
560 final SerialMappableExecutor<T> ex = new SerialMappableExecutor<T>(mappable);
561 stats = pushContextAndCall(ex, new Callable<IterationStatistics>() {
562 @Override
563 public IterationStatistics call() throws Exception {
564 return ex.call(body, type, args);
565 }
566 });
567 } else if (useParameter) {
568 ParameterUnorderedWorklist<T> wl = Priority.makeParameterUnordered();
569 final ParameterUnorderedExecutor<T> ex = new ParameterUnorderedExecutor<T>(wl);
570
571 initializeWorklist(wl, null, mappable);
572 stats = pushContextAndCall(ex, new Callable<IterationStatistics>() {
573 @Override
574 public IterationStatistics call() throws Exception {
575 return ex.call(body, type, args);
576 }
577 });
578 } else {
579 final MappableExecutor<T> ex = new MappableExecutor<T>(mappable);
580 stats = pushContextAndCall(ex, new Callable<IterationStatistics>() {
581 @Override
582 public IterationStatistics call() throws Exception {
583 return ex.call(body, type, args);
584 }
585 });
586 }
587 if (stats == null)
588 throw new Error("unknown executor");
589
590 Launcher.getLauncher().addStats(stats);
591 Features.getReplayFeature().onFinish();
592 }
593
594 private <T> void runBody(Mappable<T> mappable, LambdaVoid<T> body) throws ExecutionException {
595 checkValidity();
596 runBody(mappable, body, MappableType.TYPE_0);
597 }
598
599 private <T, A1> void runBody(Mappable<T> mappable, Lambda2Void<T, A1> body, A1 arg1) throws ExecutionException {
600 checkValidity();
601 runBody(mappable, body, MappableType.TYPE_1, arg1);
602 }
603
604 private <T, A1, A2> void runBody(Mappable<T> mappable, Lambda3Void<T, A1, A2> body, A1 arg1, A2 arg2)
605 throws ExecutionException {
606 checkValidity();
607 runBody(mappable, body, MappableType.TYPE_2, arg1, arg2);
608 }
609
610 public boolean useParameter() {
611 checkValidity();
612 return useParameter;
613 }
614
615 public boolean useSerial() {
616 checkValidity();
617 return useSerial;
618 }
619
620 public boolean ignoreUserFlags() {
621 checkValidity();
622 return ignoreUserFlags;
623 }
624
625 public boolean inRoot() {
626 checkValidity();
627 return current.executor == root;
628 }
629
630 public boolean moreStats() {
631 checkValidity();
632 return moreStats;
633 }
634
635 private static enum ExecutorType {
636 BAREBONES, UNORDERED, ORDERED;
637 }
638
639 private static class ExecutorFrame {
640 final ThreadPool pool;
641 final Executor executor;
642 final byte mask;
643
644 public ExecutorFrame(ThreadPool pool, Executor executor, byte mask) {
645 this.pool = pool;
646 this.executor = executor;
647 this.mask = mask;
648 }
649 }
650
651 private static class ThreadSuspender implements Callback {
652 private final ReentrantLock lock;
653 private final Condition cond;
654 private final int numThreads;
655
656 private int numSuspended;
657 private boolean once;
658
659 public ThreadSuspender(int numThreads) {
660 this.numThreads = numThreads;
661 lock = new ReentrantLock();
662 cond = lock.newCondition();
663 }
664
665 private void abort() {
666 // TODO(ddn): What to do for barebones executors?
667 IterationAbortException.throwException();
668 }
669
670 private void commit() {
671 Iteration it = Iteration.getCurrentIteration();
672 if (it != null)
673 it.performCommit(true);
674 }
675
676 private void reset() {
677 once = false;
678 numSuspended = 0;
679 }
680
681 public void suspend(Executor executor) throws InterruptedException {
682 lock.lock();
683 try {
684 if (once) {
685 abort();
686 return;
687 } else {
688 once = true;
689 }
690
691 executor.suspend(this);
692
693 while (numSuspended < numThreads - 1) {
694 cond.await();
695 }
696
697 executor.suspendDone();
698 reset();
699 commit();
700 } finally {
701 lock.unlock();
702 }
703 }
704
705 @Override
706 public void call() {
707 lock.lock();
708 try {
709 numSuspended++;
710
711 if (numSuspended == numThreads - 1) {
712 cond.signal();
713 }
714 } finally {
715 lock.unlock();
716 }
717 }
718 }
719
720 private static class DummyExecutor implements Executor {
721 @Override
722 public void arbitrate(Iteration current, Iteration conflicter) throws IterationAbortException {
723 }
724
725 @Override
726 public void onCommit(Iteration it, Callback action) {
727 }
728
729 @Override
730 public void onRelease(Iteration it, ReleaseCallback action) {
731 }
732
733 @Override
734 public void onUndo(Iteration it, Callback action) {
735 }
736
737 public boolean isSerial() {
738 return true;
739 }
740
741 @Override
742 public void suspend(Callback listener) {
743 throw new UnsupportedOperationException();
744 }
745
746 @Override
747 public void suspendDone() {
748 throw new UnsupportedOperationException();
749 }
750 }
751
752 private static class SimpleContext<T> extends AbstractExecutorContext<T> {
753 private final int maxThreads;
754 private final AtomicInteger current = new AtomicInteger();
755
756 public SimpleContext(int maxThreads) {
757 this.maxThreads = maxThreads;
758 }
759
760 @Override
761 public int getThreadId() {
762 return current.getAndIncrement() % maxThreads;
763 }
764
765 @Override
766 public int getIterationId() {
767 throw new UnsupportedOperationException("Not supported yet.");
768 }
769 }
770
771 private static void dumpStatistics(List<Statistics> stats, PrintStream summaryOut, PrintStream fullOut) {
772 if (stats.isEmpty())
773 return;
774
775 fullOut.println("====== Individual Statistics ======");
776 for (Statistics stat : stats) {
777 stat.dumpFull(fullOut);
778 }
779
780 List<Statistics> merged = new ArrayList<Statistics>();
781 Map<Class<? extends Statistics>, Statistics> reps = new HashMap<Class<? extends Statistics>, Statistics>();
782
783 for (Statistics stat : stats) {
784 Class<? extends Statistics> key = stat.getClass();
785 Statistics rep = reps.get(key);
786
787 if (rep == null) {
788 reps.put(key, stat);
789 merged.add(stat);
790 } else {
791 rep.merge(stat);
792 }
793 }
794
795 summaryOut.println("==== Summary Statistics ====");
796 fullOut.println("====== Merged Statistics ======");
797 for (Statistics stat : merged) {
798 stat.dumpSummary(summaryOut);
799 stat.dumpFull(fullOut);
800 }
801 }
802
803 private static void usage() {
804 System.err.println("java -cp ... galois.runtime.GaloisRuntime [options] <main class> <args>*");
805 System.err.println(" -r <num runs> : number of runs to use");
806 System.err.println(" -t <num threads> : number of threads to use");
807 System.err.println(" -f <property file> : property file to read arguments from");
808 System.err.println(" -p : use ParaMeter");
809 System.err.println(" -s : use serial data structures and executor");
810 System.err.println(" -dr : record execution for deterministic replay");
811 System.err.println(" -dp : playback execution from deterministic replay");
812 System.err.println(" -g : enable additional statistics.");
813 System.err.println(" Currently: stack profiling, processor utilization");
814 System.err.println(" --help : print help");
815 }
816
817 /**
818 * @param args
819 * @throws Exception
820 */
821 public static void main(String[] args) throws Exception {
822 String main = null;
823 String[] mainArgs = new String[0];
824 boolean useParameter = false;
825 boolean useSerial = false;
826 boolean moreStats = false;
827 boolean ignoreUserFlags = false;
828 ReplayFeature.Type replayType = ReplayFeature.Type.NO;
829 int samplerInterval = 0;
830 int numThreads = 1;
831 int numRuns = 1;
832
833 for (int i = 0; i < args.length; i++) {
834 String arg = args[i];
835 if (arg.equals("-r")) {
836 numRuns = Integer.parseInt(args[++i]);
837 } else if (arg.equals("-t")) {
838 numThreads = Integer.parseInt(args[++i]);
839 } else if (arg.equals("-p")) {
840 useParameter = true;
841 } else if (arg.equals("-f")) {
842 Properties p = new Properties(System.getProperties());
843 p.load(new FileInputStream(args[++i]));
844 System.setProperties(p);
845 } else if (arg.equals("--dr")) {
846 replayType = ReplayFeature.Type.RECORD;
847 } else if (arg.equals("-s")) {
848 useSerial = true;
849 } else if (arg.equals("--dp")) {
850 replayType = ReplayFeature.Type.PLAYBACK;
851 useSerial = true;
852 } else if (arg.equals("-g")) {
853 samplerInterval = 100;
854 moreStats = true;
855 } else if (arg.equals("-i")) {
856 ignoreUserFlags = true;
857 } else if (arg.equals("--help")) {
858 usage();
859 System.exit(1);
860 } else {
861 main = arg;
862 mainArgs = Arrays.asList(args).subList(i + 1, args.length).toArray(new String[args.length - i - 1]);
863 break;
864 }
865 }
866
867 if (main == null) {
868 usage();
869 System.exit(1);
870 }
871
872 if (useParameter) {
873 samplerInterval = 0;
874 numThreads = 1;
875 numRuns = 1;
876 }
877
878 String defaultArgs = System.getProperty("args");
879 if (defaultArgs != null) {
880 if (mainArgs.length != 0) {
881 System.err.println("'args' property and commandline args both given");
882 System.exit(1);
883 }
884 mainArgs = defaultArgs.split("\\s+");
885 }
886
887 // Run
888 RuntimeStatistics stats = new RuntimeStatistics();
889 Launcher launcher = Launcher.getLauncher();
890
891 for (int i = 0; i < numRuns; i++) {
892 if (i != 0) {
893 launcher.reset();
894 }
895
896 initialize(numThreads, useParameter, useSerial, replayType, moreStats, ignoreUserFlags);
897 Features.initialize(getRuntime().getMaxIterations(), replayType);
898
899 Sampler sampler = StackSampler.start(samplerInterval);
900 launcher.startTiming();
901 try {
902 Reflection.invokeStaticMethod(main, "main", new Object[] { mainArgs });
903 launcher.stopTiming();
904 launcher.addStats(sampler.stop());
905 long timeWithoutGc = launcher.elapsedTime(true);
906 long timeWithGc = launcher.elapsedTime(false);
907 if (logger.isLoggable(Level.INFO)) {
908 logger.info("Runtime (ms): " + timeWithGc + " (without GC: " + timeWithoutGc + ")");
909 }
910 stats.putStats(timeWithoutGc, timeWithGc);
911 } catch (Exception e) {
912 throw e;
913 }
914 }
915
916 launcher.addStats(stats);
917 PrintStream out = new PrintStream("stats.txt");
918 dumpStatistics(launcher.getStatistics(), System.out, out);
919 out.close();
920 }
921 }