Skip to content

Commit

Permalink
more comparable scaling tests
Browse files Browse the repository at this point in the history
  • Loading branch information
paxel committed Oct 1, 2023
1 parent 42a4603 commit 5e63493
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 76 deletions.
47 changes: 20 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,34 +96,27 @@ String v = dist.<String>ask(new EndMessage())

# Benchmarks

Comparison JAVA 11 GroupExecutor variant vs JAVA 21 virtual threads

Benchmark:
* create system with x actors.
* send 1000 messages to each actor
* finish and remove each actor
* wait until the result was sent to the final actor
* shutdown the system
```
Benchmark Mode Cnt Score Error Units
JmhTest.run001ActorOn001Thread thrpt 5 14807.641 ± 118.880 ops/s
JmhTest.run001Actors JAVA 21 thrpt 5 318438.884 ± 8725.628 ops/s
JmhTest.run002ActorOn001Thread thrpt 5 14793.968 ± 132.940 ops/s
JmhTest.run002Actors JAVA 21 thrpt 5 514296.649 ± 23787.449 ops/s
JmhTest.run010ActorOn001Thread thrpt 5 14767.468 ± 141.431 ops/s
JmhTest.run010ActorOn010Thread thrpt 5 122679.731 ± 2291.937 ops/s
JmhTest.run010Actors JAVA 21 thrpt 5 1141230.953 ± 21649.833 ops/s
JmhTest.run020ActorOn020Thread thrpt 5 165262.649 ± 9270.499 ops/s
JmhTest.run020Actors JAVA 21 thrpt 5 1268742.526 ± 49428.590 ops/s
JmhTest.run030ActorOn020Thread thrpt 5 164761.670 ± 5103.291 ops/s
JmhTest.run030Actors JAVA 21 thrpt 5 1268501.106 ± 93959.566 ops/s
JmhTest.run999ActorOn010Threads thrpt 5 110869.939 ± 1938.133 ops/s
JmhTest.run999Actors JAVA 21 thrpt 5 150694.498 ± 1410.907 ops/s
JmhTest.run999ActorOnWorkStealingThreads thrpt 5 4200.800 ± 109.647 ops/s
NA
Benchmark Mode Cnt Score Error Units
JmhTest.run_____1_Actors thrpt 5 317127.717 ± 8029.515 ops/s
JmhTest.run_____2_Actors thrpt 5 547704.933 ± 8683.210 ops/s
JmhTest.run____10_Actors thrpt 5 1384233.070 ± 4930.434 ops/s
JmhTest.run____20_Actors thrpt 5 1727040.878 ± 117252.943 ops/s
JmhTest.run____30_Actors thrpt 5 1847566.975 ± 252653.978 ops/s
JmhTest.run___999_Actors thrpt 5 2073771.534 ± 140663.794 ops/s
JmhTest.run_50000_Actors thrpt 5 1813868.496 ± 90683.616 ops/s
```

A big improvement performance wise with a cleaner interface to the user
A better test would be:
* setup the system before the benchmark
* send the 1000 messages to each actor
* ask each actor for the sum
* remove each actor
* shutdown the system after the benchmark

Welcome to the world of tomorrow
2 changes: 1 addition & 1 deletion src/main/java/paxel/lintstone/impl/MessageContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public <F> CompletableFuture<F> ask(String name, Object msg) throws Unregistered
throw new UnregisteredRecipientException("Actor with name " + name + " does not exist");
}
CompletableFuture<F> result = new CompletableFuture<>();
actor.get().send(msg, self, mec -> mec.otherwise((m, o) -> {
actor.get().send(msg, self, mec -> mec.otherwise((o, m) -> {
try {
result.complete((F) o);
} catch (Exception e) {
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/paxel/lintstone/api/FailingTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public void testGetDataOut() throws InterruptedException, ExecutionException {

// this message goes to an actor that wants to reply. but can't, because we are calling from outside the actor system
// so this should be a message in the errorHandler
echoActor.send("you ok?");
echoActor.send("the error log is expected.");
// this is the correct way to ask for data from outside the actorSystem
String echo = echoActor.<String>ask("please tell me").get();
assertThat(echo, is("echo"));
Expand Down
4 changes: 2 additions & 2 deletions src/test/java/paxel/lintstone/api/InternalAskTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import org.junit.Test;
import paxel.lintstone.api.actors.CharCount;
import paxel.lintstone.api.actors.Distributor;
import paxel.lintstone.api.actors.Sorter;
import paxel.lintstone.api.actors.SorterActor;
import paxel.lintstone.api.actors.WordCount;
import paxel.lintstone.api.messages.EndMessage;

Expand Down Expand Up @@ -41,7 +41,7 @@ public void testAskExternal() throws InterruptedException, ExecutionException, T
LintStoneActorAccessor dist = system.registerActor("dist", Distributor::new, ActorSettings.DEFAULT);
system.registerActor("wordCount", WordCount::new, ActorSettings.DEFAULT);
system.registerActor("charCount", CharCount::new, ActorSettings.DEFAULT);
system.registerActor("sorter", Sorter::new, ActorSettings.DEFAULT);
system.registerActor("sorter", SorterActor::new, ActorSettings.DEFAULT);

LintStoneSystem s = LintStoneSystemFactory.create();
LintStoneActorAccessor syncedOut = s.registerActor("out", () -> mec -> mec.otherwise((o, m)->System.out.println(o)), ActorSettings.DEFAULT);
Expand Down
78 changes: 40 additions & 38 deletions src/test/java/paxel/lintstone/api/JmhTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.Benchmark;
Expand All @@ -11,6 +11,7 @@
import org.openjdk.jmh.annotations.OperationsPerInvocation;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
Expand All @@ -29,66 +30,74 @@ public class JmhTest {
private static final String TEST = "Test";

@Benchmark
@OperationsPerInvocation(1000)
public void run001Actors() throws InterruptedException {
@OperationsPerInvocation(1_000)
public void run_____1_Actors(Blackhole blackhole) throws InterruptedException, ExecutionException {
int threads = 1;
int actorCount = 1;
int messages = 1000;
int messages = 1_000;

run(actorCount, messages, LintStoneSystemFactory.create());
run(actorCount, messages, LintStoneSystemFactory.create(), blackhole);
}

@Benchmark
@OperationsPerInvocation(1000)
public void run002Actors() throws InterruptedException {
@OperationsPerInvocation(2_000)
public void run_____2_Actors(Blackhole blackhole) throws InterruptedException, ExecutionException {
int threads = 1;
int actorCount = 2;
int messages = 1000;
int messages = 2_000;

run(actorCount, messages, LintStoneSystemFactory.create());
run(actorCount, messages, LintStoneSystemFactory.create(), blackhole);
}

@Benchmark
@OperationsPerInvocation(1000)
public void run010Actors() throws InterruptedException {
@OperationsPerInvocation(10_000)
public void run____10_Actors(Blackhole blackhole) throws InterruptedException, ExecutionException {
int actorCount = 10;
int messages = 1000;
int messages = 10_000;

run(actorCount, messages, LintStoneSystemFactory.create());
run(actorCount, messages, LintStoneSystemFactory.create(), blackhole);
}


@Benchmark
@OperationsPerInvocation(1000)
public void run020Actors() throws InterruptedException {
@OperationsPerInvocation(20_000)
public void run____20_Actors(Blackhole blackhole) throws InterruptedException, ExecutionException {
int actorCount = 20;
int messages = 1000;
int messages = 20_000;

run(actorCount, messages, LintStoneSystemFactory.create());
run(actorCount, messages, LintStoneSystemFactory.create(), blackhole);
}

@Benchmark
@OperationsPerInvocation(1000)
public void run030Actors() throws InterruptedException {
@OperationsPerInvocation(30_000)
public void run____30_Actors(Blackhole blackhole) throws InterruptedException, ExecutionException {
int actorCount = 30;
int messages = 1000;
int messages = 30_000;

run(actorCount, messages, LintStoneSystemFactory.create());
run(actorCount, messages, LintStoneSystemFactory.create(), blackhole);
}

@Benchmark
@OperationsPerInvocation(1000)
public void run999Actors() throws InterruptedException {
@OperationsPerInvocation(999_000)
public void run___999_Actors(Blackhole blackhole) throws InterruptedException, ExecutionException {
int actorCount = 999;
int messages = 1000;
int messages = 999_000;

run(actorCount, messages, LintStoneSystemFactory.create());
run(actorCount, messages, LintStoneSystemFactory.create(), blackhole);
}


private void run(int actorCount, int messages, LintStoneSystem system) throws InterruptedException, UnregisteredRecipientException {
CountDownLatch latch = new CountDownLatch(actorCount);
system.registerActor("END", () -> new EndActor(latch), ActorSettings.DEFAULT);
@Benchmark
@OperationsPerInvocation(50_000_000)
public void run_50000_Actors(Blackhole blackhole) throws InterruptedException, ExecutionException {
int actorCount = 50_000;
int messages = 50_000_000;

run(actorCount, messages, LintStoneSystemFactory.create(), blackhole);
}


private void run(int actorCount, int messages, LintStoneSystem system, Blackhole blackhole) throws InterruptedException, UnregisteredRecipientException, ExecutionException {
List<LintStoneActorAccessor> actors = new ArrayList<>();
for (int i = 0; i < actorCount; i++) {
actors.add(system.registerActor(TEST + i, MessageActor::new, ActorSettings.DEFAULT));
Expand All @@ -98,9 +107,9 @@ private void run(int actorCount, int messages, LintStoneSystem system) throws In
}
for (int i = 0; i < actorCount; i++) {
// finish the actors
actors.get(i).send("END");
Integer end = actors.get(i).<Integer>ask("END").get();
blackhole.consume(end);
}
latch.await();
system.shutDownAndWait();
}

Expand All @@ -112,13 +121,6 @@ public static void main(String[] args) throws RunnerException {
new Runner(opt).run();
}

private record EndActor(CountDownLatch latch) implements LintStoneActor {

@Override
public void newMessageEvent(LintStoneMessageEventContext mec) {
latch.countDown();
}
}

private static class MessageActor implements LintStoneActor {

Expand All @@ -139,7 +141,7 @@ public void newMessageEvent(LintStoneMessageEventContext mec) {
}
).inCase(String.class, (name, reply) -> {
// notify to the given name, the sum
reply.send(name, sum);
reply.reply(sum);
// and kill yourself
reply.unregister();
}).otherwise((a, b) -> System.err.println("unknown message: " + a));
Expand Down
7 changes: 3 additions & 4 deletions src/test/java/paxel/lintstone/api/actors/Distributor.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@ private void send(String txt, LintStoneMessageEventContext mec) {
}

private void handleEnd(EndMessage dmg, LintStoneMessageEventContext askContext) {
CompletableFuture<Integer> words = new CompletableFuture<>();
CompletableFuture<Integer> chars = new CompletableFuture<>();
CompletableFuture<String> sort = new CompletableFuture<>();
// each of these completes will be called in the thread context of this actor
askContext.ask("wordCount", new EndMessage(), c -> c.inCase(Integer.class, (r, replyContext) -> words.complete(r)));
askContext.ask("charCount", new EndMessage(), c -> c.inCase(Integer.class, (r, replyContext) -> chars.complete(r)));
CompletableFuture<Integer> words = askContext.ask("wordCount", new EndMessage());
CompletableFuture<Integer> chars = askContext.ask("charCount", new EndMessage());
// other way to ask
askContext.ask("sorter", new EndMessage(), c -> c.inCase(String.class, (r, replyContext) -> sort.complete(r)));

// when the last reply comes, the reply of the external ask is fulfilled.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import java.util.*;
import java.util.stream.Collectors;

public class Sorter implements LintStoneActor {
public class SorterActor implements LintStoneActor {
final Set<String> words = new HashSet<>();

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class WordGeneratorActor implements LintStoneActor {
public record Init(Long seed) {
}

public record Request(int sylibls) {
public record Request(int syllables) {
}

public record Word(String value) {
Expand All @@ -39,7 +39,7 @@ private void createWord(Request request, LintStoneMessageEventContext lintStoneM
if (random == null)
reinit(0L);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < request.sylibls(); i++) {
for (int i = 0; i < request.syllables(); i++) {
stringBuilder.append(consonants.get(random.nextDouble()));
stringBuilder.append(vocals.get(random.nextDouble()));
}
Expand Down

0 comments on commit 5e63493

Please sign in to comment.