From 952f1fd2d686ea5b6e57275699d5466987655e44 Mon Sep 17 00:00:00 2001 From: unknown <david.antunes-da-silva@irit.fr> Date: Thu, 21 Jul 2022 15:16:52 +0200 Subject: [PATCH] add FairOrderCycling scheduler + some fixes for MonoThreadedCycling and for philosophers example --- src/example/philosophes/MainPhilosophe.java | 46 ++-- src/example/philosophes/Philosopher.java | 5 +- src/example/philosophes/Waste.java | 5 +- .../schedulers/FairOrderCycling.java | 225 ++++++++++++++++++ .../schedulers/FairPosCycling.java | 65 ----- .../schedulers/MonoThreadedCycling.java | 8 +- 6 files changed, 265 insertions(+), 89 deletions(-) create mode 100644 src/mas/implementation/schedulers/FairOrderCycling.java delete mode 100644 src/mas/implementation/schedulers/FairPosCycling.java diff --git a/src/example/philosophes/MainPhilosophe.java b/src/example/philosophes/MainPhilosophe.java index d228b7a..e3d7b30 100644 --- a/src/example/philosophes/MainPhilosophe.java +++ b/src/example/philosophes/MainPhilosophe.java @@ -1,7 +1,7 @@ package example.philosophes; import mas.core.Cyclable; -import mas.implementation.schedulers.MonoThreadedCycling; +import mas.implementation.schedulers.FairCycling; import java.util.ArrayList; import java.util.List; @@ -10,7 +10,13 @@ public class MainPhilosophe { public static void main(String[] args) { - class MyFairCycling extends MonoThreadedCycling<Cyclable> { + int nbCycles = 100; + int nAgents = 100; + + /** + * An extension of the scheduler to make some performance tests + */ + class MyFairCycling extends FairCycling<Cyclable> { long startTimeCycle = 0; @@ -22,7 +28,7 @@ public class MainPhilosophe { @Override public boolean stopCondition() { - return nbOfCycles == 1000; + return nbOfCycles == nbCycles; } @Override @@ -41,9 +47,6 @@ public class MainPhilosophe { } } - int nAgents = 100; - int nbCycles = 1000; - Philosopher[] philosophers = new Philosopher[nAgents]; Fork[] forks = new Fork[nAgents]; @@ -60,9 +63,26 @@ public class MainPhilosophe { philosophers[i].setRightPhilosopher(philosophers[(i+1) % nAgents]); } + //Sequential execution + sequentialPerformanceTest(100, philosophers); + + + //Amak execution MyFairCycling scheduler = new MyFairCycling(philosophers); scheduler.setSleep(0); + final long startTime = System.nanoTime(); + + scheduler.start(); + + scheduler.waitUntilFinish(); + + final long endTime = System.nanoTime(); + System.out.println("AMAk : Total execution time: " + (endTime / 1000 - startTime / 1000) + " microseconds"); + System.out.println("\tCycle moyen : " + scheduler.getCycleTime() / 1000 + " microseconds"); + } + + public static void sequentialPerformanceTest(int nbCycles, Cyclable... cyclables){ final long startTimeSequential = System.nanoTime(); int nbCycle = 0; @@ -72,8 +92,8 @@ public class MainPhilosophe { while(nbCycle < nbCycles){ startTimeCycleSequential = System.nanoTime(); - for(Philosopher philosopher : philosophers){ - philosopher.cycle(); + for(Cyclable cyclable : cyclables){ + cyclable.cycle(); } cycleTimeSequential.add(System.nanoTime() - startTimeCycleSequential); @@ -85,15 +105,5 @@ public class MainPhilosophe { System.out.println("Iterative : Total execution time: " + (endTimeSequential / 1000 - startTimeSequential / 1000) + " microseconds"); System.out.println("\tCycle : " + cycleTimeSequential.stream().mapToLong(value -> value).average().orElse(0.0) /1000 + " microseconds"); - - final long startTime = System.nanoTime(); - - scheduler.start(); - - scheduler.waitUntilFinish(); - - final long endTime = System.nanoTime(); - System.out.println("AMAk : Total execution time: " + (endTime / 1000 - startTime / 1000) + " microseconds"); - System.out.println("\tCycle moyen : " + scheduler.getCycleTime() / 1000 + " microseconds"); } } diff --git a/src/example/philosophes/Philosopher.java b/src/example/philosophes/Philosopher.java index 555c9ba..0408e7e 100644 --- a/src/example/philosophes/Philosopher.java +++ b/src/example/philosophes/Philosopher.java @@ -120,8 +120,11 @@ public class Philosopher extends Agent { @Override public void act() { //System.out.println("Philosopher num " + id + " act"); + //Add some complexity to the agent fibonacciRecursion(23); - scheduler.addCyclable(new Waste(id)); + if(scheduler != null){ + scheduler.addCyclable(new Waste(id)); + } } public int fibonacciRecursion(int n){ diff --git a/src/example/philosophes/Waste.java b/src/example/philosophes/Waste.java index 8d0f84e..8e32e93 100644 --- a/src/example/philosophes/Waste.java +++ b/src/example/philosophes/Waste.java @@ -3,6 +3,9 @@ package example.philosophes; import mas.core.Cyclable; import mas.core.Scheduler; +/** + * This class is useful to see how the scheduler adds new cyclables to the system dynamically. + */ public class Waste implements Cyclable { private int id; @@ -15,7 +18,7 @@ public class Waste implements Cyclable { } @Override public void cycle() { - /*System.out.println("I'm the waste n°" + id);*/ + //System.out.println("I'm the waste n°" + id); } @Override diff --git a/src/mas/implementation/schedulers/FairOrderCycling.java b/src/mas/implementation/schedulers/FairOrderCycling.java new file mode 100644 index 0000000..35708d7 --- /dev/null +++ b/src/mas/implementation/schedulers/FairOrderCycling.java @@ -0,0 +1,225 @@ +package mas.implementation.schedulers; + +import mas.core.Cyclable; +import mas.core.Scheduler; +import mas.core.Sleepable; + +import java.util.*; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; + +/** + * The FairOrderCycling is a one thread scheduler which maintains the same execution order of the cyclables every system's cycle. + * + * @param <T> + * Extended class of {@link mas.core.Cyclable} + * + * @author David Antunes + */ +public class FairOrderCycling<T extends Cyclable> implements Scheduler<T>, Sleepable { + + /** + * The cyclable objects handled by the scheduler. + */ + protected List<T> cyclables = new ArrayList<>(); + + /** + * The cyclables that must be added in the next cycle. + */ + protected Queue<T> pendingToAddCyclables = new ConcurrentLinkedQueue<>(); + + /** + * The cyclables that must be removed in the next cycle. + */ + protected Queue<T> pendingToRemoveCyclables = new ConcurrentLinkedQueue<>(); + + /** + * Time between two cycles. Default time in {@link Sleepable#DEFAULT_SLEEP}. + */ + protected int sleep = DEFAULT_SLEEP; + + /** + * Number of system cycles. + */ + protected int nbOfCycles = 0; + + /** + * Condition to know if the scheduler must be stopped. + */ + protected boolean mustStop = false; + + /** + * Condition to know if the scheduler must be paused. + */ + protected boolean mustPause = false; + + /** + * Object used to pause the scheduler. + */ + protected CountDownLatch pauseLatch; + + /** + * The thread which executes the cycle. + */ + Thread executionThread = new Thread(this::doCycle); + + /** + * Constructor which set the initial cyclables. + * + * @param cyclables + * The corresponding cyclables + */ + public FairOrderCycling(T... cyclables){ + for(T cyclable : cyclables){ + addCyclable(cyclable); + } + } + + @Override + public void start() { + executionThread.start(); + } + + @Override + public void stop() { + mustStop = true; + } + + @Override + public void pause() { + if(pauseLatch == null || pauseLatch.getCount() == 0){ + pauseLatch = new CountDownLatch(1); + } + mustPause = true; + } + + @Override + public void resume() { + if(pauseLatch != null){ + pauseLatch.countDown(); + } + } + + @Override + public void addCyclable(T cyclable) { + cyclable.setScheduler(this); + pendingToAddCyclables.add(cyclable); + } + + @Override + public boolean stopCondition() { + return false; + } + + @Override + public boolean isFinished() { + return !executionThread.isAlive(); + } + + @Override + public void waitUntilFinish() { + try { + executionThread.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @Override + public int getSleep() { + return sleep; + } + + @Override + public void setSleep(int sleep) { + this.sleep = sleep; + } + + @Override + public void doSleep() { + if (getSleep() != 0) { + try { + Thread.sleep(sleep); + } catch (final InterruptedException e) { + e.printStackTrace(); + } + } + } + + /** + * Executes {@link #step()} until the scheduler must stop. + */ + protected void doCycle(){ + while(!mustStop){ + step(); + if(stopCondition()){ + this.stop(); + } + + if(mustPause){ + try{ + pauseLatch.await(); + } catch (InterruptedException e){ + throw new RuntimeException(e); + } + } + } + } + + /** + * Executes a system's cycle. + */ + protected void step(){ + onCycleStarts(); + + treatPendingCyclables(); + + for(int i = 0; i< cyclables.size(); i++){ + T cyclable = cyclables.get(i); + cyclable.cycle(); + if(cyclable.terminate()){ + pendingToRemoveCyclables.add(cyclable); + } + } + + doSleep(); + + onCycleEnds(); + + nbOfCycles++; + } + + /** + * Add the cyclables that are going to be scheduled on the current cycle and remove those that are not going to be scheduled. + */ + protected void treatPendingCyclables() { + cyclables.removeAll(pendingToRemoveCyclables); + cyclables.addAll(pendingToAddCyclables); + + pendingToRemoveCyclables.clear(); + pendingToAddCyclables.clear(); + } + + /** + * This method is called at the end of every system's cycle. + */ + protected void onCycleEnds() { + + } + + /** + * This method is called at the start of every system's cycle. + */ + protected void onCycleStarts(){ + + } + + /** + * Getter for the number of cycles. + * + * @return the number of cycles performed by the system + */ + public int getNbOfCycles() { + return nbOfCycles; + } +} diff --git a/src/mas/implementation/schedulers/FairPosCycling.java b/src/mas/implementation/schedulers/FairPosCycling.java deleted file mode 100644 index c87a5e1..0000000 --- a/src/mas/implementation/schedulers/FairPosCycling.java +++ /dev/null @@ -1,65 +0,0 @@ -package mas.implementation.schedulers; - -import mas.core.Cyclable; -import mas.core.Scheduler; -import mas.core.Sleepable; - -/** - * Même que MonoThreadedCycling + equitable sur position des Round Robin - */ -public class FairPosCycling implements Scheduler, Sleepable { - @Override - public void start() { - - } - - @Override - public void stop() { - - } - - @Override - public void pause() { - - } - - @Override - public void resume() { - - } - - @Override - public void addCyclable(Cyclable cyclable) { - - } - - @Override - public int getSleep() { - return 0; - } - - @Override - public void setSleep(int sleep) { - - } - - @Override - public void doSleep() { - - } - - @Override - public boolean stopCondition() { - return false; - } - - @Override - public boolean isFinished() { - return false; - } - - @Override - public void waitUntilFinish() { - - } -} diff --git a/src/mas/implementation/schedulers/MonoThreadedCycling.java b/src/mas/implementation/schedulers/MonoThreadedCycling.java index 15af4a5..4957f53 100644 --- a/src/mas/implementation/schedulers/MonoThreadedCycling.java +++ b/src/mas/implementation/schedulers/MonoThreadedCycling.java @@ -4,9 +4,7 @@ import mas.core.Cyclable; import mas.core.Scheduler; import mas.core.Sleepable; -import java.util.LinkedHashSet; -import java.util.Queue; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CountDownLatch; @@ -25,7 +23,7 @@ public class MonoThreadedCycling<T extends Cyclable> implements Scheduler<T>, Sl /** * The cyclable objects handled by the scheduler. */ - protected Set<T> cyclables = new LinkedHashSet<>(); + protected List<T> cyclables = new ArrayList<>(); /** * The cyclables that must be added in the next cycle. @@ -195,6 +193,8 @@ public class MonoThreadedCycling<T extends Cyclable> implements Scheduler<T>, Sl */ protected void treatPendingCyclables() { cyclables.addAll(pendingToAddCyclables); + Collections.shuffle(cyclables); + pendingToAddCyclables.clear(); } -- GitLab