Message Switching Test
This example is meant to get a feel for the message switching speed of the CellSpeak Virtual
Machine. The speed with which a message is exchanged between two cells depends on many factors:
the speed of the machine, the number of cores, whether the cells are running on the same machine,
in the same process, the size of the message and so forth.
The message switch inside the CellSpeak Virtual Machine will choose a different approach depending
on these factors and will always try to deliver the message as fast as possible.
The program below will give you a good feel for the type of speeds and throughput that can be handled by the
CellSpeak message switch. It implements two tests, the first test focuses on delivering many small
messages - like the parameters in a function call - whereas the second test sends larger messages
to test the bandwith of the message switch. On my computer small messages are sent and received at
a rate of around 3 million messages per second. For the large messages, the bandwith reaches around 10 GBytes/second.
(1) We do not bother to define a type - there is only one such variable - a name spared.
(2) This counts as a single expression, so we can use the short form of the function definition.
(3) We derive the type of the parameter simply by stating that it is the same as the type of the variable T.
08 Message Switching Test.celsrc
use Windows, Math, Strings, Editor, System
group Legion
design Legatus is
const int NrOfCohorts = 10
const int NrOfTestRounds = 10
cell Window
int Rounds = 1
cell Centurions[NrOfCohorts]
ansi TestCommand
(1) var Test is record
float msec
int Messages
int KBytes
int Replies
ClockClass Clock
word StartTime
function Reset is
msec = Messages = KBytes = Replies = 0
StartTime = Clock.Ticks()
end
function Stop => msec = Clock.Duration( StartTime )
function Report(cell Window) is
Window <- print("\n\t[msec] msec for [Messages/1000] KMsg => [Messages/msec] KMsg/sec")
KBytes ? Window <- print("\n\t[KBytes/1000] MBytes were sent/rcvd in [msec] msec - throughput => [KBytes/msec] MBytes/sec")
end
end
var AllTests is record
float msec
int NrOfTests
int Messages
int KBytes
(2) function Reset => msec = NrOfTests = Messages = KBytes = 0
function Report(cell Window) is
Window <- print("\n\n\tAfter [NrOfTests] tests: [msec/1000] seconds for [Messages/1000] KMsg => [Messages/msec] KMsg/sec")
KBytes ? Window <- print("\n\t[KBytes/1000] MBytes were sent/rcvd in [msec/1000] sec - throughput => [KBytes/msec] MBytes/sec")
end
(3) function Add( var T like Test ) is
msec += T.msec
Messages += T.Messages
T.KBytes ? KBytes += T.KBytes
NrOfTests += 1
end
end
constructor is
Test.Clock.Create()
Window = create MenuWindow("Message switching test")
system <- stdout.Set( Window )
Test.Reset()
for each Centurion in Centurions do
Centurion = create CenturionDesign(self)
Centurion <- AreYouReady
end
end
on Paratus do
Test.Replies += 1
if Test.Replies is NrOfCohorts then
Window <- print("
Small Message test
------------------
There are 10 Cohorts of 500 Legionaries each.
Each Legionary will send 200 messages to its Centurion and the Centurion then send the results
for his Cohort back to the Legatus of the Legion. This means that for each test 1 million messages
are sent and received (not counting the message traffic between the Centurii and the Legatus).
The test is repeated [NrOfTestRounds] times.\n")
AllTests.Reset()
Test.Reset()
TestCommand = "SmallMessageTest"
for each Centurion in Centurions => Centurion <- (TestCommand)
end
end
on Results( int Messages, int Bytes ) do
Test.Replies += 1
Test.Messages += Messages
Bytes ? Test.KBytes += Bytes / 1000
if Test.Replies is NrOfCohorts then
Test.Stop()
AllTests.Add( Test )
Test.Report( Window )
//system <- MessageSwitch.GetStatus
if AllTests.NrOfTests is NrOfTestRounds then
AllTests.Report(Window)
if TestCommand is "SmallMessageTest" then
Window <- print("
Big Message test
----------------
Each Legionary will send 20 messages with random length between 0 and 64KBytes to its Centurion.
Each Cohort will therefore send approximately 500 * 20 * 32 KBytes = 320 MBytes, so all cohorts together
will send around 3.2 GBytes in 100,000 messages.
The test is also repeated [NrOfTestRounds] times.\n")
TestCommand = "BigMessageTest"
Test.Reset()
AllTests.Reset()
for each Centurion in Centurions => Centurion <- (TestCommand)
end
else
Test.Reset()
for each Centurion in Centurions => Centurion <- (TestCommand)
end
end
end
end
design CenturionDesign(cell Legatus) is
keep Legatus
const int NrOfLegionaries = 500
const int NrOfSmallMessages = 200
const int NrOfBigMessages = 20
int NrOfReplies = 0
int Messages = 0
int Bytes =0
cell Cohort = create CohortDesign( NrOfLegionaries )
on AreYouReady do
Legatus <- Paratus
end
on SmallMessageTest do
NrOfReplies = Messages = Bytes = 0
Cohort <- SendSmallMessages( NrOfSmallMessages )
end
on BigMessageTest do
NrOfReplies = Messages = Bytes = 0
Cohort <- SendBigMessages( NrOfBigMessages )
end
on TestMessage(int a, float b, xyz vector) do
Messages += 1
end
on TestMessage(byte[] M) do
Messages += 1
Bytes += nel M
end
on AllMessagesSent do
NrOfReplies += 1
NrOfReplies is NrOfLegionaries ? Legatus <- Results( Messages, Bytes )
end
end
design CohortDesign( int NrOfLegionaries ) is
constructor is
for i = 1 to NrOfLegionaries => create LegionaryDesign
end
on ? => all <- (same)
end
design LegionaryDesign is
on SendSmallMessages(int NrOfMessages) do
for i = 1 to NrOfMessages => sender <- TestMessage( 10, 20.5, [1,2,3] )
sender <- AllMessagesSent
end
int NrOfMessages
cell Destination
function CheckAndSend is
byte BigMessage[ randi() and 0x0000FFFF ]
(NrOfMessages -~ 1) ? Destination <+- TestMessage( BigMessage ) : Destination <- AllMessagesSent
end
on SendBigMessages(int NrOfMessages) do
keep NrOfMessages
Destination = sender
CheckAndSend()
end
on TestMessage.DN do
CheckAndSend()
end
end