/* * Copyright (c) 2009 Stanford University, unless otherwise specified. * All rights reserved. * * This software was developed by the Pervasive Parallelism Laboratory of * Stanford University, California, USA. * * Permission to use, copy, modify, and distribute this software in source * or binary form for any purpose with or without fee is hereby granted, * provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of Stanford University nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ package edu.stanford.ppl.concurrent; import java.util.concurrent.CyclicBarrier; public class ParUtil { public interface Block { void call(int index); } private static class RunnableBlock implements Block { private final Runnable _task; RunnableBlock(final Runnable task) { _task = task; } public void call(final int index) { _task.run(); } } public static void parallel(final int numThreads, final Runnable block) { parallel(numThreads, new RunnableBlock(block)); } public static void parallel(final int numThreads, final Block block) { final Thread[] threads = new Thread[numThreads]; final Throwable[] failure = { null }; for (int i = 0; i < threads.length; ++i) { final int index = i; threads[i] = new Thread("worker #" + i) { @Override public void run() { try { block.call(index); } catch (final Throwable xx) { failure[0] = xx; } } }; } for (Thread t : threads) { t.start(); } for (Thread t : threads) { try { t.join(); } catch (final InterruptedException xx) { throw new RuntimeException("unexpected", xx); } } if (failure[0] instanceof RuntimeException) { throw (RuntimeException) failure[0]; } else if (failure[0] instanceof Error) { throw (Error) failure[0]; } else { assert(failure[0] == null); } } /** Returns the elapsed milliseconds. */ public static long timeParallel(final int numThreads, final Runnable block) { return timeParallel(numThreads, new RunnableBlock(block)); } /** Returns the elapsed milliseconds. */ public static long timeParallel(final int numThreads, final Block block) { final long[] times = new long[2]; final CyclicBarrier barrier = new CyclicBarrier(numThreads, new Runnable() { public void run() { times[0] = times[1]; times[1] = System.currentTimeMillis(); } }); parallel(numThreads, new Block() { public void call(final int index) { try { barrier.await(); } catch (final Exception xx) { throw new RuntimeException("unexpected", xx); } try { block.call(index); } finally { try { barrier.await(); } catch (final Exception xx) { throw new RuntimeException("unexpected", xx); } } } }); return times[1] - times[0]; } }