Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 14 additions & 30 deletions Akka/README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,19 @@
# Setup #
# Setup

Please install [sbt]("http://www.scala-sbt.org/0.13/docs/Setup.html"), [scala]("http://www.scala-lang.org/download/install.html").
Install [sbt]("http://www.scala-sbt.org/0.13/docs/Setup.html") and [scala]("http://www.scala-lang.org/download/install.html"). On Ubuntu, this can be done with the following commands:

# Benchmarks #
echo "deb https://dl.bintray.com/sbt/debian /" | sudo tee -a /etc/apt/sources.list.d/sbt.list
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823
sudo apt-get update
sudo apt-get install sbt scala

There are 7 benchmark programs. Descriptions of them could be found in the [Theater benchmark suite](Theater/README.md)
# Usage

To run Ring:
sbt "run-main Ring <ring_size> <num_of_rounds>"
sbt "run-main BusyRing <ring_size> <num_of_messages>"
sbt "run-main Fork <depth>"
sbt "run-main TreeMsg <depth> <num_msg>"
sbt "run-main Pipeline <num_request>"
sbt "run-main Chameneos <num_cham> <num_host>"
sbt "run-main Calculator <num_expressions> <num_operators> <num_workers>"

sbt "run-main Ring <ring_size> <num_of_rounds>"

To run Ring2:

sbt "run-main Ring <ring_size> <initial_message_value>"

To run Fork:

sbt "run-main Fork <depth>"

To run TreeMsg:

sbt "run-main TreeMsg <depth> <num_msg>"

To run Pipeline:

sbt "run-main <num_request>"

To run Chameneos:

sbt "run-main <num_cham> <num_host>"

To run Calculator:

sbt "run-main <num_expressions> <num_operators> <num_workers>"
53 changes: 53 additions & 0 deletions Akka/src/main/scala/BusyRing.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import java.util.Calendar
import akka.actor._

object BusyRing {
val system = ActorSystem("BusyRing")
var startTime: Long = 0
var endTime: Long = 0

def main(args: Array[String]): Unit = {
val numNodes = args(0).toInt
val numMessages = args(1).toInt
val nodes =
for (i <- 0 until numNodes) yield system.actorOf(Props(classOf[RingNode], i, numMessages), "Node" + i)
for (i <- 0 until numNodes) nodes(i) ! Connect(nodes((i + 1) % numNodes))
nodes(0) ! Start
}

case object Start
case object Stop
case class Connect(next: ActorRef)
case class Token(goal: Int)

class RingNode(val nodeId: Int, val numMessages: Int) extends Actor {
var nextNode: ActorRef = context.system.deadLetters
var completed: Int = 0

def receive = {
case Connect(next: ActorRef) =>
// println(s"Actor $nodeId is connecting to ${next.path}")
nextNode = next

case Start =>
println("Start: \t" + Calendar.getInstance().getTime)
BusyRing.startTime = System.currentTimeMillis()
1 to numMessages foreach { _ =>
nextNode ! Token(nodeId)
}

case Token(goal) =>
if (goal == nodeId) {
completed += 1
if (completed == numMessages) {
BusyRing.endTime = System.currentTimeMillis()
println("Stop: \t" + Calendar.getInstance().getTime)
println(s"Elapsed time: ${(BusyRing.endTime - BusyRing.startTime) / 1000.0}s")
system.shutdown()
}
} else {
nextNode ! Token(goal)
}
}
}
}
58 changes: 19 additions & 39 deletions Akka/src/main/scala/Ring.scala
Original file line number Diff line number Diff line change
@@ -1,71 +1,51 @@
import java.util.Calendar
import akka.actor._

import akka.actor.{Actor, ActorRef, ActorSystem, Props}

/**
* @author chupanw
*/
object Ring {

val system = ActorSystem()

val system = ActorSystem("Ring")
var startTime: Long = 0
var endTime: Long = 0

def main(args: Array[String]): Unit = {
val numNodes = args(0).toInt
val numRounds = args(1).toInt
run(numNodes = numNodes, numRounds = numRounds)
}

def run(numNodes: Int, numRounds: Int): Unit = {
val nodes = spawnNodes(numNodes, numRounds)
nodes(0) ! Start
}

def spawnNodes(numNodes: Int, numRounds: Int): Array[ActorRef] = {
val nodes =
for (i <- 0 until numNodes) yield system.actorOf(Props(classOf[NodeActor], i, numRounds), "Node" + i)
for (i <- 0 until numNodes) yield system.actorOf(Props(classOf[RingNode], i, numRounds), "Node" + i)
for (i <- 0 until numNodes) nodes(i) ! Connect(nodes((i + 1) % numNodes))
nodes.toArray
nodes(0) ! Start
}

// Messages
case object Start
case object Stop
case class Connect(next: ActorRef)
case class Token(id: Int)

class NodeActor(val nodeId: Int, val numRounds: Int) extends Actor {
case class Token(goal: Int, lapsRemaining: Int)

class RingNode(val nodeId: Int, val numRounds: Int) extends Actor {
var nextNode: ActorRef = context.system.deadLetters
var returnCount: Int = 0

def receive = {

case Connect(next: ActorRef) =>
// println(s"Actor $nodeId is connecting to ${next.path}")
// println(s"Actor $nodeId is connecting to ${next.path}")
nextNode = next

case Start =>
startTime = System.currentTimeMillis()
println("Start: \t" + Calendar.getInstance().getTime)
1 to numRounds foreach {_ =>
nextNode ! Token(nodeId)
}
Ring.startTime = System.currentTimeMillis()
nextNode ! Token(nodeId, numRounds)

case Token(id) =>
if (id == nodeId) {
returnCount += 1
if (returnCount == numRounds) {
case Token(goal, lapsRemaining) =>
if (goal == nodeId) {
if (lapsRemaining == 1) {
Ring.endTime = System.currentTimeMillis()
println("Stop: \t" + Calendar.getInstance().getTime)
println(s"Duration: ${(Ring.endTime - Ring.startTime) / 1000.0}s")
System.exit(0)
println(s"Elapsed time: ${(Ring.endTime - Ring.startTime) / 1000.0}s")
system.shutdown()
} else {
nextNode ! Token(goal, lapsRemaining - 1)
}
} else {
nextNode ! Token(goal, lapsRemaining)
}
nextNode ! Token(id)
}
}

}
}
71 changes: 0 additions & 71 deletions Akka/src/main/scala/Ring2.scala

This file was deleted.

58 changes: 56 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,57 @@
# Actor Benchmark #
# ActorBench

There are 7 benchmark programs right now. Each of them has a Akka version (with Scala 2.11.8) and a Theater version (with Swift 3.0).
ActorBench is a suite of microbenchmarks designed to measure various aspects of an actor programming framework. Currently, implementations exist for:

- Akka/Scala
- Theater/Swift

See `READMD.md` under each implementation's directory for usage instructions.

# Benchmarks

## Ring

This is an implementation of the Ring benchmark, as described in [*Programming Erlang*](http://pragprog.com/book/jaerlang/programming-erlang), for which there many solutions on the web. N actors are created in a ring. A message is sent around the ring for M times so that a total of N * M messages get sent. At all times, there is only one message in flight.

Purpose: actor scheduling overhead

## BusyRing

This modified version of the Ring benchmark sends M messages along a ring of N actors. Each message travels along the ring exactly once.

Purpose: throughput

## Fork

Starting from a root actor, each actor creates two child actors and form a binary tree. The <depth> parameter specifies the maximum depth of the tree.

Purpose: actor creation time

## TreeMsg

This benchmark creates an actor tree and then send messages from root to leaves. The tree creation process is the same as in Fork. After actor tree is created, root actor sends <num_msg> messages to its children. Non-leaf nodes simply forward messages to their children, and leaf nodes send ACKs back to root node. If root node receives enough ACKs, it terminates the program.

Purpose: efficiency of actor lookup process

## Pipeline

This benchmark simulates a 3-stage message processing pipeline. The pipeline looks like this: downloader -> indexer -> writer. In the beginning, <num_request> request messages are sent to downloader. Each request message contains a string "Requested ". Downlaoder substitutes "Requested" with "Downloaded", and later indexer changes "Downloaded" to "Indexed", and finally writer changes "Indexed" to "Written".

Purpose: throughput of stateless actors

## Chameneos

This is an implementation of the [Chameneos concurrency benchmark](https://benchmarksgame.alioth.debian.org/u64q/chameneosredux-description.html#chameneosredux). Two kinds of actor are created, one Mall actor and N Chameneos actors (N > 2). Chameneos meet other Chameneos at the Mall. A Chameneos indicates its wish to meet another Chameneos by sending a Meeting message to the Mall, which will either:

1. put that Chameneos in a waiting slot if there is no other Chameneos waiting to meet, or
2. forward that Meeting message to the awaiting Chameneos.

When two Chameneos meet, they change their colors (internal state) and then resume sending more Meeting requests to the Mall. The Mall can host at most M Chameneos at a time. If the limit is reached, the Mall tells all incoming Chameneos to stop. After getting exit confirmation from each Chameneos, the program stops.

Purpose: throughput of stateful actors

## Calculator

A Master actor accepts <num_expressions> requests and forward them to its workers randomly. The number of workers is specified by <num_workers>. When a worker receives the forwarded request from master, it generates a random arithmetic expression, computes the result, and increases the counter. Each random arithmetic expression contains <num_operators> basic arithmetic operators (e.g. +, -, \*, /).

Purpose: scheduling of master/worker model