package edu.rice.hj.example.comp322.labs.lab8; import edu.rice.hj.runtime.actors.Actor; import java.math.BigDecimal; import java.util.concurrent.atomic.AtomicInteger; import static edu.rice.hj.Module1.finish; import static edu.rice.hj.Module1.launchHabaneroApp; /* * This class runs a actor version of computing pi by * setting a threshold value. */ public class PiActor2 { public static void main(final String[] args) { final int scale; // Default scale is 5000, if user does not specify one if (args.length > 0) { scale = Integer.parseInt(args[0]); } else { scale = 5000; } System.out.println("required precision = " + scale); final int numWorkers = 48; launchHabaneroApp(() -> { for (int iter = 0; iter < 8; iter++) { final long startTime = System.nanoTime(); final Master2 master = new Master2(numWorkers, scale); finish(() -> { master.start(); }); final long endTime = System.nanoTime(); final long execTime = (long) ((endTime - startTime) / 1e6); System.out.println("PI = " + master.getResult()); System.out.println("Iteration-" + iter + " Exec Time = " + execTime + " ms."); } }); } // Message classes private static class StopMessage2 { public static StopMessage2 ONLY = new StopMessage2(); } private static class WorkMessage2 { public final int scale; public final int term; public WorkMessage2(final int scale, final int term) { this.scale = scale; this.term = term; } } private static class ResultMessage2 { public final BigDecimal result; public final int workerId; public ResultMessage2(final BigDecimal result, final int workerId) { this.result = result; this.workerId = workerId; } } /* * A master actor. */ private static class Master2 extends Actor { // start: do not mess with these private final int numWorkers; private final int scale; private final Worker2[] workers; // end: do not mess with these // use result to accumulate the value of PI private BigDecimal result = BigDecimal.ZERO; // use tolerance to decide when it is okay to request termination of workers private BigDecimal tolerance; // use counter to track number of workers that have terminated private AtomicInteger numWorkersTerminated = new AtomicInteger(0); // use counter to track how many terms have been requested private int numTermsRequested = 0; public Master2(final int numWorkers, final int scale) { this.numWorkers = numWorkers; this.scale = scale; this.tolerance = BigDecimal.ONE.movePointLeft(scale); this.workers = new Worker2[numWorkers]; } public void onPostStart() { // now start the workers for (int i = 0; i < numWorkers; i++) { workers[i] = new Worker2(this, i); workers[i].start(); } // TODO send some work to workers in advance, generateWork() should be useful } /** * Generates work for the given worker * * @param workerId the id of te worker to send work */ private void generateWork(int workerId) { // send work request to specified worker final WorkMessage2 wm = new WorkMessage2(scale, numTermsRequested); workers[workerId].send(wm); // update the limit for the series requested so far numTermsRequested += 1; } public void requestWorkersToExit() { // TODO request all workers to exit via the StopMessage2 } protected void process(final Object msg) { if (msg instanceof ResultMessage2) { // a message sent from a worker about the term it computed ResultMessage2 rm = (ResultMessage2) msg; result = result.add(rm.result); // TODO If we reached our precision, we can request workers to terminate // TODO else we generate some more work to keep the worker busy } else if (msg instanceof StopMessage2) { // a message sent from a worker that it is terminating // TODO track how many workers terminated // TODO master can terminate (via exit()) only if all workers have terminated } } public String getResult() { return result.toPlainString(); } } /* * A worker actor. */ private static class Worker2 extends Actor { private final Master2 master; private final int id; public Worker2(final Master2 master, final int id) { this.master = master; this.id = id; } protected void process(final Object msg) { if (msg instanceof StopMessage2) { // TODO let master know worker is terminating by sending a message // TODO terminate this } else if (msg instanceof WorkMessage2) { // master requested computation of a term WorkMessage2 wm = (WorkMessage2) msg; // do some more computation BigDecimal result = PiUtil.calculateBbpTerm(wm.scale, wm.term); master.send(new ResultMessage2(result, id)); } } } }