/** * */ package org.squirrelframework.foundation.fsm; import static org.junit.Assert.assertEquals; import java.util.concurrent.CyclicBarrier; import org.junit.Test; import org.squirrelframework.foundation.fsm.annotation.StateMachineParameters; import org.squirrelframework.foundation.fsm.impl.AbstractUntypedStateMachine; import org.squirrelframework.foundation.fsm.threadsafe.BarrierThread; public class PerformanceTest { enum FSMEvent { ToA, ToB, ToC, ToD } @StateMachineParameters(stateType = String.class, eventType = FSMEvent.class, contextType = Integer.class) static class StateMachineSample extends AbstractUntypedStateMachine { } @Test(timeout = 10000) public void manyTransitions() { performTest(10000, false, null); } @Test public void manyTransitionWithMonitor() { performTest(1000, true, null); } // @Test // public void comparePerfMonitorOverload() { // Runnable task = new Runnable() { // @Override // public void run() { // calculatePi(100); // } // }; // // int testIter = 100; // for(int i=0; i<4; ++i) { // performTest(testIter, false, task); // performTest(testIter, true, task); // } // // int iterTimes = 20; // float overloadTimes=0; // for(int i=0; i<iterTimes; ++i) { // Stopwatch watch1 = new Stopwatch().start(); // performTest(testIter, false, task); // long time1 = watch1.stop().elapsedMillis(); // System.out.println("Task 1 finished in "+time1+"ms."); // // Stopwatch watch2 = new Stopwatch().start(); // performTest(testIter, true, task); // long time2 = watch2.stop().elapsedMillis(); // System.out.println("Task 2 finished in "+time2+"ms."); // float overloadTime = time2-time1; // overloadTimes+=overloadTime; // System.out.println("--------------------------------------"); // } // System.out.println("Average overload for each transition is "+ // String.format("%.4f", overloadTimes/iterTimes/testIter/4)+"ms."); // } // // private BigDecimal calculatePi(int iterTimes) { // BigDecimal sum = new BigDecimal(0); // final sum // BigDecimal term = new BigDecimal(0); // term without sign // BigDecimal sign = new BigDecimal(1.0); // sign on each term // // BigDecimal one = new BigDecimal(1.0); // BigDecimal two = new BigDecimal(2.0); // // for (int k = 0; k < iterTimes; k++) { // BigDecimal count = new BigDecimal(k); // //term = 1.0/(2.0*k + 1.0); // BigDecimal temp1 = two.multiply(count); // BigDecimal temp2 = temp1.add(one); // term = one.divide(temp2,50,BigDecimal.ROUND_FLOOR); // //sum = sum + sign*term; // BigDecimal temp3 = sign.multiply(term); // sum = sum.add(temp3); // sign = sign.negate(); // } // BigDecimal pi = new BigDecimal(0); // BigDecimal four = new BigDecimal(4); // pi = sum.multiply(four); // return pi; // } void performTest(final int iterTimes, final boolean addPerfMonitor, final Runnable task) { UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(StateMachineSample.class); UntypedAnonymousAction action = new UntypedAnonymousAction() { @Override public void execute(Object from, Object to, Object event, Object context, UntypedStateMachine stateMachine) { if(task!=null) task.run(); } }; builder.externalTransition().from("D").to("A").on(FSMEvent.ToA).perform(action); builder.externalTransition().from("A").to("B").on(FSMEvent.ToB).perform(action); builder.externalTransition().from("B").to("C").on(FSMEvent.ToC).perform(action); builder.externalTransition().from("C").to("D").on(FSMEvent.ToD).perform(action); final UntypedStateMachine fsm1 = builder.newStateMachine("D"); final UntypedStateMachine fsm2 = builder.newStateMachine("D"); Runnable showPerfResult = null; if(addPerfMonitor) { final StateMachinePerformanceMonitor performanceMonitor = new StateMachinePerformanceMonitor(fsm1.getClass().getName()); fsm1.addDeclarativeListener(performanceMonitor); fsm2.addDeclarativeListener(performanceMonitor); showPerfResult = new Runnable() { @Override public void run() { fsm1.removeDeclarativeListener(performanceMonitor); fsm2.removeDeclarativeListener(performanceMonitor); StateMachinePerformanceModel perfModel = performanceMonitor.getPerfModel(); long totalTimes = 2*4*iterTimes; assertEquals(perfModel.getTotalTransitionInvokedTimes(), totalTimes); assertEquals(perfModel.getTotalActionInvokedTimes(), totalTimes); // System.out.println(perfModel); } }; } CyclicBarrier entryBarrier = new CyclicBarrier(2); CyclicBarrier exitBarrier = new CyclicBarrier(3); new BarrierThread(new Runnable() { @Override public void run() { for (int i = 0; i < iterTimes; i++) { fsm1.fire(FSMEvent.ToA, 10); fsm1.fire(FSMEvent.ToB, 10); fsm1.fire(FSMEvent.ToC, 10); fsm1.fire(FSMEvent.ToD, 10); } } }, "Performance-Test-Thread-1", entryBarrier, exitBarrier).start(); new BarrierThread(new Runnable() { @Override public void run() { for (int i = 0; i < iterTimes; i++) { fsm2.fire(FSMEvent.ToA, 10); fsm2.fire(FSMEvent.ToB, 10); fsm2.fire(FSMEvent.ToC, 10); fsm2.fire(FSMEvent.ToD, 10); } } }, "Performance-Test-Thread-2", entryBarrier, exitBarrier).start(); try { exitBarrier.await(); } catch (Exception e) { throw new RuntimeException(e); } if(showPerfResult!=null) { showPerfResult.run(); } } }