// Copyright © 2012-2020 VLINGO LABS. All rights reserved. // // This Source Code Form is subject to the terms of the // Mozilla Public License, v. 2.0. If a copy of the MPL // was not distributed with this file, You can obtain // one at https://mozilla.org/MPL/2.0/. package io.vlingo.actors.plugin.mailbox.sharedringbuffer; import static org.junit.Assert.assertEquals; import java.util.Properties; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Ignore; import org.junit.Test; import io.vlingo.actors.Actor; import io.vlingo.actors.ActorsTest; import io.vlingo.actors.Definition; import io.vlingo.actors.plugin.PluginProperties; import io.vlingo.actors.plugin.completes.PooledCompletesPlugin; import io.vlingo.actors.testkit.AccessSafely; public class RingBufferMailboxActorTest extends ActorsTest { private static final int MailboxSize = 64; private static final int MaxCount = 1024; private static final int ThroughputMailboxSize = 1048576; private static final int ThroughputMaxCount = 4194304; // 104857600; private static final int ThroughputWarmUpCount = 4194304; @Test public void testBasicDispatch() throws Exception { init(MailboxSize); final TestResults testResults = new TestResults(MaxCount); final CountTaker countTaker = world.actorFor( CountTaker.class, Definition.has(CountTakerActor.class, Definition.parameters(testResults), "testRingMailbox", "countTaker-1")); testResults.setMaximum(MaxCount); for (int count = 1; count <= MaxCount; ++count) { countTaker.take(count); } assertEquals(MaxCount, testResults.getHighest()); } @Ignore @Test public void testThroughput() throws Exception { System.out.println("WARMING UP..."); init(ThroughputMailboxSize); final TestResults testResults = new TestResults(ThroughputMailboxSize); final CountTaker countTaker = world.actorFor( CountTaker.class, Definition.has(ThroughputCountTakerActor.class, Definition.parameters(testResults), "testRingMailbox", "countTaker-2")); testResults.setMaximum(ThroughputWarmUpCount); for (int count = 1; count <= ThroughputWarmUpCount; ++count) { countTaker.take(count); } while (testResults.getHighest() < ThroughputWarmUpCount) ; System.out.println("STARTING TEST..."); testResults.setHighest(0); testResults.setMaximum(ThroughputMaxCount); final long startTime = System.currentTimeMillis(); for (int count = 1; count <= ThroughputMaxCount; ++count) { countTaker.take(count); } while (testResults.getHighest() < ThroughputMaxCount) ; final long ticks = System.currentTimeMillis() - startTime; System.out.println("TICKS: " + ticks + " FOR " + ThroughputMaxCount + " MESSAGES IS " + (ThroughputMaxCount / ticks * 1000) + " PER SECOND"); assertEquals(ThroughputMaxCount, testResults.getHighest()); } private void init(final int mailboxSize) { Properties properties = new Properties(); properties.setProperty("plugin.name.testRingMailbox", "true"); properties.setProperty("plugin.testRingMailbox.classname", "io.vlingo.actors.plugin.mailbox.sharedringbuffer.SharedRingBufferMailboxPlugin"); properties.setProperty("plugin.testRingMailbox.defaultMailbox", "false"); properties.setProperty("plugin.testRingMailbox.size", ""+mailboxSize); properties.setProperty("plugin.testRingMailbox.fixedBackoff", "2"); properties.setProperty("plugin.testRingMailbox.numberOfDispatchersFactor", "1.0"); properties.setProperty("plugin.testRingMailbox.dispatcherThrottlingCount", "20"); SharedRingBufferMailboxPlugin provider = new SharedRingBufferMailboxPlugin(); final PluginProperties pluginProperties = new PluginProperties("testRingMailbox", properties); final PooledCompletesPlugin plugin = new PooledCompletesPlugin(); plugin.configuration().buildWith(world.configuration(), pluginProperties); provider.start(world); } public static interface CountTaker { void take(final int count); } public static class CountTakerActor extends Actor implements CountTaker { @SuppressWarnings("unused") private CountTaker self; private final TestResults testResults; public CountTakerActor(final TestResults testResults) { this.testResults = testResults; self = selfAs(CountTaker.class); } @Override public void take(final int count) { if (testResults.isHighest(count)) { testResults.setHighest(count); } } } public static class ThroughputCountTakerActor extends Actor implements CountTaker { private final TestResults testResults; public ThroughputCountTakerActor(final TestResults testResults) { this.testResults = testResults; } @Override public void take(final int count) { testResults.setHighest(count); } } private static class TestResults { private final AccessSafely accessSafely; private TestResults(final int happenings) { final AtomicInteger highest = new AtomicInteger(0); final AtomicInteger maximum = new AtomicInteger(0); this.accessSafely = AccessSafely .afterCompleting(happenings) .writingWith("highest", highest::set) .readingWith("highest", highest::get) .writingWith("maximum", maximum::set) .readingWith("maximum", maximum::get) .readingWith("isHighest", (Integer count) -> count > highest.get()); } void setHighest(Integer value) { this.accessSafely.writeUsing("highest", value); } void setMaximum(Integer value) { this.accessSafely.writeUsing("maximum", value); } int getHighest(){ return this.accessSafely.readFrom("highest"); } @SuppressWarnings("unused") int getMaximum(){ return this.accessSafely.readFrom("maximum"); } boolean isHighest(Integer value){ return this.accessSafely.readFromNow("isHighest", value); } } }