This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Actor messaging throughput test

No replies
Seung Jun
Joined: 2009-07-20,
User offline. Last seen 42 years 45 weeks ago.
As I found the Actor concept wonderful, I gave it a quick throughput test, hoping it is almost as efficient as a method call (because a message passing is conceptually like a method invocation).  I ran the code (attached at the bottom) that forms a 8-node ring and circulates a token on it (10 million rounds total).  It was tested on a 2.8 GHz 8-core Solaris box with more than enough memory.  I used Scala 2.7.5.  The throughput is not as good as I hoped - although 14 usec per hop isn't too bad, I hoped it would be better (particularly with loop-react).

[while-receive results]
1083616.107189 ms total, 0.10836161071889999 ms per round, 0.013545201339862499 ms per hop, 73826.88340387204 hops per second.

If while-receive is replaced with loop-react, the throughput becomes about halved.  One thing I noticed is that there were 16 active threads running for the 8-node ring, which seems to indicate each actor is comprised of two threads (in the while-receive case, I saw 8 active threads, which makes sense).  Can anyone explain why 16 threads had to be actively used with loop-react, which seems counter-intuitive given what react is supposed to be?

[loop-react results]
2251426.823 ms total, 0.22514268229999998 ms per round, 0.028142835287499997 ms per hop, 35533.02251831616 hops per second.

My questions are

1. Are these results expected?  Anyone please submit your results (on this code or similar)?

2. Can I improve my code for better performance?

3. Why were 16 threads running actively with loop-react?

I'll note that I tested with ringSize set to 4 as well, which didn't change the throughput results much.

Any comments and insights welcome.  Thank you.

Seung

object RingTest {
    val ringSize = 8
    val maxRounds = 10000000

    case object Token
    case object Exit
    case class NextNode(passer: Actor)

    val LOG = LogFactory.getLogger(getClass().getName())
   
    class Node(id: Int) extends Actor {
        var nextNode: Actor = null
       
        override def act() {
            var round = 0
            val startTime = System.nanoTime
            while (true) {
                receive {
                    case Token =>
                        // Pass the token aggressively before doing anything.
                        assert(nextNode != null)
                        nextNode ! Token

                        round += 1

                        if (round % 10000 == 0) {
                            LOG.info("id=" + id + " round=" + round)
                        }

                        if (round == maxRounds) {
                            val endTime = System.nanoTime
                            printStats(startTime, endTime)
                            System.exit(0)
                        }

                    case NextNode(x) =>
                        nextNode = x
                }
            }
        }
       
        private def printStats(startTime: Long, endTime: Long) {
            val timeTotal = (endTime - startTime) / 1000000.0
            val timePerRound = timeTotal / maxRounds
            val timePerHop = timePerRound / ringSize
            LOG.info("" + timeTotal + " ms total, " +
                     timePerRound + " ms per round, " +
                     timePerHop + " ms per hop, " +
                     (1000 / timePerHop) + " hops per second.")
        }
    }

    def logConfigs() {
        LOG.config("ring size = " + ringSize)
        LOG.config("max rounds = " + maxRounds)
    }

    def main(args: Array[String]) {
        val nodes = new Array[Actor](ringSize)
       
        for (i <- 0 until ringSize) {
            nodes(i) = new Node(i)
            nodes(i).start()
        }

        for (i <- 0 until ringSize) {
            nodes(i) ! new NextNode(nodes((i + 1) % ringSize))
        }

        nodes(0) ! Token
        LOG.info("Passed the token.")
    }
}

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland