/*
This file is part of JOP, the Java Optimized Processor
see <http://www.jopdesign.com/>
Copyright (C) 2009-2010, Martin Schoeberl (martin@jopdesign.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package jembench;
/**
* A minimal framework for work distribution to the CMP cores.
*
* @author Martin Schoeberl (martin@jopdesign.com)
*
*/
public class EnumeratedExecutor {
/**
* A helper class that runs forever and executes work
* if there is some more to do.
*
* @author martin
*
*/
private class Worker extends Thread {
volatile boolean finished;
WorkUnit ex;
public Worker() {
finished = true;
}
void setExecute(WorkUnit e) {
ex = e;
}
public void run() {
for (;;) {
if (cnt<size && !finished) {
int i;
synchronized(ex) {
i = cnt++;
}
if (i<size) {
ex.executeUnit(i);
}
} else {
finished = true;
if (requestStop) {
// break out and terminate this thread
break;
}
}
}
}
}
/** tracking the work done by all runners */
private volatile int cnt;
/** size of workload */
private volatile int size;
/** Executor not needed anymore - stop threads */
private volatile boolean requestStop;
private Worker runner[];
int cpus = Util.getNrOfCores();
public EnumeratedExecutor() {
runner = new Worker[cpus-1];
}
/**
* Create and start all worker threads
*/
public void start() {
requestStop = false;
for (int i=0; i<cpus-1; i++) {
runner[i] = new Worker();
runner[i].start();
}
}
/**
* Request termination from the worker threads
*/
public void stop() {
requestStop = true;
// we could do some waiting for the terminating threads....
}
public void executeParallel(WorkUnit e, int size) {
this.size = size;
cnt = 0;
// distribute the work to all cores.
for (int i=0; i<cpus-1; ++i) {
runner[i].setExecute(e);
runner[i].finished = false;
}
// do also some work
while (cnt<size) {
int i;
synchronized(e) {
i = cnt++;
}
if (i<size) {
e.executeUnit(i);
}
}
// Now wait for others finishing their work.
// We could use join, but the following is
// also OK.
boolean allFinished;
do {
allFinished = true;
for (int i=0; i<cpus-1; ++i) {
allFinished &= runner[i].finished;
}
} while (!allFinished);
// now we can return
// that would be a serial version for tests:
// for (int i=0; i<size; ++i) {
// e.execute(i);
// }
}
/**
* Just a simple main for the usage example
* @param args
*/
public static void main(String[] args) {
WorkUnit e = new Test();
EnumeratedExecutor pe = new EnumeratedExecutor();
pe.start();
pe.executeParallel(e, e.getNrOfUnits());
pe.stop();
Test.result();
}
/**
* An example how to use the executor framework.
*
* @author martin
*
*/
private static class Test implements WorkUnit {
final static int N = 20;
static int a[] = new int[N];
static int cnt;
public void executeUnit(int nr) {
synchronized (this) {
a[nr] = ++cnt;
}
// waste some time with busy wait
long t = System.currentTimeMillis();
while (System.currentTimeMillis()-t < 10) {
;
}
}
public static void result() {
for (int i=0; i<N; ++i) {
System.out.println(a[i]);
}
}
public int getNrOfUnits() {
return N;
}
}
}