-- Copyright: Mario Schweigler, Adam Sampson (C) 2005-2006
-- Institution: Computing Laboratory, University of Kent, Canterbury, UK
-- Description: Demo app for pony: ping-pong time benchmark
--              (requires the `BENCHMARK.PINGPONGTIME' pre-processor
--              constant to be defined in `ponyinttcpip.occ')

-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-- MA 02110-1301, USA.

#INCLUDE "course.module"
#INCLUDE "pony.module"
#INCLUDE "trace.inc"

--{{{  Sequential protocols
PROTOCOL SEQPROT.1.1 IS [1]BYTE:
PROTOCOL SEQPROT.1.2 IS [1]BYTE; [1]BYTE:
PROTOCOL SEQPROT.1.3 IS [1]BYTE; [1]BYTE; [1]BYTE:
PROTOCOL SEQPROT.1.4 IS [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE:
PROTOCOL SEQPROT.1.5 IS [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE:
PROTOCOL SEQPROT.1.6 IS [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE:
PROTOCOL SEQPROT.1.7 IS [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE:
PROTOCOL SEQPROT.1.8 IS [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE:
PROTOCOL SEQPROT.1.9 IS [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE:
PROTOCOL SEQPROT.1.10 IS [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE; [1]BYTE:
PROTOCOL SEQPROT.1000.1 IS [1000]BYTE:
PROTOCOL SEQPROT.1000.2 IS [1000]BYTE; [1000]BYTE:
PROTOCOL SEQPROT.1000.3 IS [1000]BYTE; [1000]BYTE; [1000]BYTE:
PROTOCOL SEQPROT.1000.4 IS [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE:
PROTOCOL SEQPROT.1000.5 IS [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE:
PROTOCOL SEQPROT.1000.6 IS [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE:
PROTOCOL SEQPROT.1000.7 IS [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE:
PROTOCOL SEQPROT.1000.8 IS [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE:
PROTOCOL SEQPROT.1000.9 IS [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE:
PROTOCOL SEQPROT.1000.10 IS [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE; [1000]BYTE:
PROTOCOL SEQPROT.1000000.1 IS [1000000]BYTE:
PROTOCOL SEQPROT.1000000.2 IS [1000000]BYTE; [1000000]BYTE:
PROTOCOL SEQPROT.1000000.3 IS [1000000]BYTE; [1000000]BYTE; [1000000]BYTE:
PROTOCOL SEQPROT.1000000.4 IS [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE:
PROTOCOL SEQPROT.1000000.5 IS [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE:
PROTOCOL SEQPROT.1000000.6 IS [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE:
PROTOCOL SEQPROT.1000000.7 IS [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE:
PROTOCOL SEQPROT.1000000.8 IS [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE:
PROTOCOL SEQPROT.1000000.9 IS [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE:
PROTOCOL SEQPROT.1000000.10 IS [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE; [1000000]BYTE:
--}}}

--{{{  CHAN TYPE THING
CHAN TYPE THING
  MOBILE RECORD
    CHAN [1]BYTE c.1?:
    CHAN [5]BYTE c.5?:
    CHAN [10]BYTE c.10?:
    CHAN [50]BYTE c.50?:
    CHAN [100]BYTE c.100?:
    CHAN [500]BYTE c.500?:
    CHAN [1000]BYTE c.1000?:
    CHAN [5000]BYTE c.5000?:
    CHAN [10000]BYTE c.10000?:
    CHAN [50000]BYTE c.50000?:
    CHAN [100000]BYTE c.100000?:
    CHAN [500000]BYTE c.500000?:
    CHAN [1000000]BYTE c.1000000?:
    CHAN SEQPROT.1.1 c.seqprot.1.1?:
    CHAN SEQPROT.1.2 c.seqprot.1.2?:
    CHAN SEQPROT.1.3 c.seqprot.1.3?:
    CHAN SEQPROT.1.4 c.seqprot.1.4?:
    CHAN SEQPROT.1.5 c.seqprot.1.5?:
    CHAN SEQPROT.1.6 c.seqprot.1.6?:
    CHAN SEQPROT.1.7 c.seqprot.1.7?:
    CHAN SEQPROT.1.8 c.seqprot.1.8?:
    CHAN SEQPROT.1.9 c.seqprot.1.9?:
    CHAN SEQPROT.1.10 c.seqprot.1.10?:
    CHAN SEQPROT.1000.1 c.seqprot.1000.1?:
    CHAN SEQPROT.1000.2 c.seqprot.1000.2?:
    CHAN SEQPROT.1000.3 c.seqprot.1000.3?:
    CHAN SEQPROT.1000.4 c.seqprot.1000.4?:
    CHAN SEQPROT.1000.5 c.seqprot.1000.5?:
    CHAN SEQPROT.1000.6 c.seqprot.1000.6?:
    CHAN SEQPROT.1000.7 c.seqprot.1000.7?:
    CHAN SEQPROT.1000.8 c.seqprot.1000.8?:
    CHAN SEQPROT.1000.9 c.seqprot.1000.9?:
    CHAN SEQPROT.1000.10 c.seqprot.1000.10?:
    CHAN SEQPROT.1000000.1 c.seqprot.1000000.1?:
    CHAN SEQPROT.1000000.2 c.seqprot.1000000.2?:
    CHAN SEQPROT.1000000.3 c.seqprot.1000000.3?:
    CHAN SEQPROT.1000000.4 c.seqprot.1000000.4?:
    CHAN SEQPROT.1000000.5 c.seqprot.1000000.5?:
    CHAN SEQPROT.1000000.6 c.seqprot.1000000.6?:
    CHAN SEQPROT.1000000.7 c.seqprot.1000000.7?:
    CHAN SEQPROT.1000000.8 c.seqprot.1000000.8?:
    CHAN SEQPROT.1000000.9 c.seqprot.1000000.9?:
    CHAN SEQPROT.1000000.10 c.seqprot.1000000.10?:
:
--}}}

PROC bmpingpongtime (CHAN BYTE key?, CHAN BYTE err!)
  MOBILE []BYTE ans.name, app.name, node.name:
  INT node.type, own.node.id, result:
  SHARED PONY.NETHANDLE! net.handle:
  PONY.ERRHANDLE! err.handle:
  INT err.point:
  SEQ
    ans.name := ""
    app.name := "bmpingpongtime"
    node.name := ""
    --{{{  Get node-type
    node.type := -1
    CHAN GETOPT opts:
    PAR
      file.get.options ("ms", opts!)
      INITIAL BOOL running IS TRUE:
      WHILE running
        BYTE b:
        opts ? CASE
          opt ; b
            CASE b
              'm'
                SEQ
                  C.trace ("bmpingpongtime: will be master")
                  node.type := PONYC.NODETYPE.MASTERRESET
              's'
                SEQ
                  C.trace ("bmpingpongtime: will be slave")
                  node.type := PONYC.NODETYPE.SLAVEWAIT
          done
            running := FALSE
    IF
      node.type = (-1)
        SEQ
          C.trace ("bmpingpongtime: you must specify either master (-m) or slave (-s) mode")
          STOP
      TRUE
        SKIP
    --}}}
    --{{{  Startup
    pony.startup.snh.ueh.iep (PONYC.NETTYPE.TCPIP, ans.name,
                              app.name, node.name, node.type,
                              own.node.id,
                              net.handle,
                              err.handle, err.point,
                              result)
    --}}}
    IF
      result = PONYC.RESULT.STARTUP.OK
        SEQ
          CASE node.type
            PONYC.NODETYPE.MASTERRESET
              THING? svr:
              SEQ
                C.trace ("bmpingpongtime: Press key to start alloc.")
                BYTE any:
                key ? any
                C.trace ("bmpingpongtime: Master starting, alloc...")
                CLAIM net.handle!
                  pony.alloc.us (net.handle, "thing", PONYC.SHARETYPE.UNSHARED, svr, result)
                ASSERT (result = PONYC.RESULT.ALLOC.OK)
                C.trace ("bmpingpongtime: Press key to quit.")
                BYTE any:
                key ? any
                C.trace ("bmpingpongtime: Master done")
            PONYC.NODETYPE.SLAVEWAIT
              VAL []INT SIZES IS [1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000, 500000, 1000000]:
              VAL []INT LENGTHS IS [i = 1 FOR 10 | i]:
              VAL INT NUM.TESTS IS 3:
              VAL INT WARMUP.LOOPS IS 10000:
              VAL INT MEASURE.LOOPS IS 100000:
              [NUM.TESTS][(SIZE SIZES) + (SIZE LENGTHS)]INT results:
              THING! cli:
              SEQ
                C.trace ("bmpingpongtime: Slave starting")
                CLAIM net.handle!
                  pony.alloc.uc (net.handle, "thing", PONYC.SHARETYPE.UNSHARED, cli, result)
                ASSERT (result = PONYC.RESULT.ALLOC.OK)
                --{{{  run tests with different packet sizes
                [1]BYTE data.1:
                [5]BYTE data.5:
                [10]BYTE data.10:
                [50]BYTE data.50:
                [100]BYTE data.100:
                [500]BYTE data.500:
                [1000]BYTE data.1000:
                [5000]BYTE data.5000:
                [10000]BYTE data.10000:
                [50000]BYTE data.50000:
                [100000]BYTE data.100000:
                [500000]BYTE data.500000:
                [1000000]BYTE data.1000000:
                SEQ k = 0 FOR NUM.TESTS
                  SEQ j = 0 FOR SIZE SIZES
                    VAL INT size IS SIZES[j]:
                    TIMER tim:
                    INT start, end:
                    SEQ
                      C.trace.i ("bmpingpongtime: Measuring with packet size: ", size)
                      --{{{  Run through depending on size
                      CASE size
                        1
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.1] ! data.1
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.1] ! data.1
                            tim ? end
                          --}}}
                        5
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.5] ! data.5
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.5] ! data.5
                            tim ? end
                          --}}}
                        10
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.10] ! data.10
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.10] ! data.10
                            tim ? end
                          --}}}
                        50
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.50] ! data.50
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.50] ! data.50
                            tim ? end
                          --}}}
                        100
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.100] ! data.100
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.100] ! data.100
                            tim ? end
                          --}}}
                        500
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.500] ! data.500
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.500] ! data.500
                            tim ? end
                          --}}}
                        1000
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.1000] ! data.1000
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.1000] ! data.1000
                            tim ? end
                          --}}}
                        5000
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.5000] ! data.5000
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.5000] ! data.5000
                            tim ? end
                          --}}}
                        10000
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.10000] ! data.10000
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.10000] ! data.10000
                            tim ? end
                          --}}}
                        50000
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.50000] ! data.50000
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.50000] ! data.50000
                            tim ? end
                          --}}}
                        100000
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.100000] ! data.100000
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.100000] ! data.100000
                            tim ? end
                          --}}}
                        500000
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.500000] ! data.500000
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.500000] ! data.500000
                            tim ? end
                          --}}}
                        1000000
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.1000000] ! data.1000000
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.1000000] ! data.1000000
                            tim ? end
                          --}}}
                      --}}}
                      VAL INT total IS end MINUS start:
                      VAL INT ns IS INT ROUND (((REAL32 ROUND total) * 1000.0) / (REAL32 ROUND MEASURE.LOOPS)):
                      SEQ
                        C.trace.i ("                     Time taken (us): ", total)
                        C.trace.i ("                     Time per communication (ns): ", ns)
                        results[k][j] := ns
                --}}}
                --{{{  Output results for gnuplot
                SEQ i = 0 FOR SIZE SIZES
                  [NUM.TESTS + 1]INT data:
                  SEQ
                    data[0] := SIZES[i]
                    SEQ j = 0 FOR NUM.TESTS
                      data[j + 1] := results[j][i]
                    C.trace.results (data)
                --}}}
                --{{{  run tests with different protocol lengths (packet size 1)
                [1]BYTE data:
                SEQ k = 0 FOR NUM.TESTS
                  SEQ j = 0 FOR SIZE LENGTHS
                    VAL INT length IS LENGTHS[j]:
                    TIMER tim:
                    INT start, end:
                    SEQ
                      C.trace.i ("bmpingpongtime: Packet size: 1. Measuring with protocol length: ", length)
                      --{{{  Run through depending on length
                      CASE length
                        1
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1.1] ! data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1.1] ! data
                            tim ? end
                          --}}}
                        2
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1.2] ! data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1.2] ! data; data
                            tim ? end
                          --}}}
                        3
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1.3] ! data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1.3] ! data; data; data
                            tim ? end
                          --}}}
                        4
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1.4] ! data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1.4] ! data; data; data; data
                            tim ? end
                          --}}}
                        5
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1.5] ! data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1.5] ! data; data; data; data; data
                            tim ? end
                          --}}}
                        6
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1.6] ! data; data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1.6] ! data; data; data; data; data; data
                            tim ? end
                          --}}}
                        7
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1.7] ! data; data; data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1.7] ! data; data; data; data; data; data; data
                            tim ? end
                          --}}}
                        8
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1.8] ! data; data; data; data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1.8] ! data; data; data; data; data; data; data; data
                            tim ? end
                          --}}}
                        9
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1.9] ! data; data; data; data; data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1.9] ! data; data; data; data; data; data; data; data; data
                            tim ? end
                          --}}}
                        10
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1.10] ! data; data; data; data; data; data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1.10] ! data; data; data; data; data; data; data; data; data; data
                            tim ? end
                          --}}}
                      --}}}
                      VAL INT total IS end MINUS start:
                      VAL INT ns IS INT ROUND (((REAL32 ROUND total) * 1000.0) / (REAL32 ROUND MEASURE.LOOPS)):
                      SEQ
                        C.trace.i ("                     Time taken (us): ", total)
                        C.trace.i ("                     Time per communication (ns): ", ns)
                        results[k][j] := ns
                --}}}
                --{{{  Output results for gnuplot
                SEQ i = 0 FOR SIZE LENGTHS
                  [NUM.TESTS + 1]INT data:
                  SEQ
                    data[0] := LENGTHS[i]
                    SEQ j = 0 FOR NUM.TESTS
                      data[j + 1] := results[j][i]
                    C.trace.results (data)
                --}}}
                --{{{  run tests with different protocol lengths (packet size 1000)
                [1000]BYTE data:
                SEQ k = 0 FOR NUM.TESTS
                  SEQ j = 0 FOR SIZE LENGTHS
                    VAL INT length IS LENGTHS[j]:
                    TIMER tim:
                    INT start, end:
                    SEQ
                      C.trace.i ("bmpingpongtime: Packet size: 1000. Measuring with protocol length: ", length)
                      --{{{  Run through depending on length
                      CASE length
                        1
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000.1] ! data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000.1] ! data
                            tim ? end
                          --}}}
                        2
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000.2] ! data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000.2] ! data; data
                            tim ? end
                          --}}}
                        3
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000.3] ! data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000.3] ! data; data; data
                            tim ? end
                          --}}}
                        4
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000.4] ! data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000.4] ! data; data; data; data
                            tim ? end
                          --}}}
                        5
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000.5] ! data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000.5] ! data; data; data; data; data
                            tim ? end
                          --}}}
                        6
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000.6] ! data; data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000.6] ! data; data; data; data; data; data
                            tim ? end
                          --}}}
                        7
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000.7] ! data; data; data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000.7] ! data; data; data; data; data; data; data
                            tim ? end
                          --}}}
                        8
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000.8] ! data; data; data; data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000.8] ! data; data; data; data; data; data; data; data
                            tim ? end
                          --}}}
                        9
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000.9] ! data; data; data; data; data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000.9] ! data; data; data; data; data; data; data; data; data
                            tim ? end
                          --}}}
                        10
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000.10] ! data; data; data; data; data; data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000.10] ! data; data; data; data; data; data; data; data; data; data
                            tim ? end
                          --}}}
                      --}}}
                      VAL INT total IS end MINUS start:
                      VAL INT ns IS INT ROUND (((REAL32 ROUND total) * 1000.0) / (REAL32 ROUND MEASURE.LOOPS)):
                      SEQ
                        C.trace.i ("                     Time taken (us): ", total)
                        C.trace.i ("                     Time per communication (ns): ", ns)
                        results[k][j] := ns
                --}}}
                --{{{  Output results for gnuplot
                SEQ i = 0 FOR SIZE LENGTHS
                  [NUM.TESTS + 1]INT data:
                  SEQ
                    data[0] := LENGTHS[i]
                    SEQ j = 0 FOR NUM.TESTS
                      data[j + 1] := results[j][i]
                    C.trace.results (data)
                --}}}
                --{{{  run tests with different protocol lengths (packet size 1000000)
                VAL INT WARMUP.LOOPS IS 100:
                VAL INT MEASURE.LOOPS IS 1000:
                [1000000]BYTE data:
                SEQ k = 0 FOR NUM.TESTS
                  SEQ j = 0 FOR SIZE LENGTHS
                    VAL INT length IS LENGTHS[j]:
                    TIMER tim:
                    INT start, end:
                    SEQ
                      C.trace.i ("bmpingpongtime: Packet size: 1000000. Measuring with protocol length: ", length)
                      --{{{  Run through depending on length
                      CASE length
                        1
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000000.1] ! data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000000.1] ! data
                            tim ? end
                          --}}}
                        2
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000000.2] ! data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000000.2] ! data; data
                            tim ? end
                          --}}}
                        3
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000000.3] ! data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000000.3] ! data; data; data
                            tim ? end
                          --}}}
                        4
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000000.4] ! data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000000.4] ! data; data; data; data
                            tim ? end
                          --}}}
                        5
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000000.5] ! data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000000.5] ! data; data; data; data; data
                            tim ? end
                          --}}}
                        6
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000000.6] ! data; data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000000.6] ! data; data; data; data; data; data
                            tim ? end
                          --}}}
                        7
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000000.7] ! data; data; data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000000.7] ! data; data; data; data; data; data; data
                            tim ? end
                          --}}}
                        8
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000000.8] ! data; data; data; data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000000.8] ! data; data; data; data; data; data; data; data
                            tim ? end
                          --}}}
                        9
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000000.9] ! data; data; data; data; data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000000.9] ! data; data; data; data; data; data; data; data; data
                            tim ? end
                          --}}}
                        10
                          --{{{  Run through
                          SEQ
                            SEQ i = 0 FOR WARMUP.LOOPS
                              cli[c.seqprot.1000000.10] ! data; data; data; data; data; data; data; data; data; data
                            tim ? start
                            SEQ i = 0 FOR MEASURE.LOOPS
                              cli[c.seqprot.1000000.10] ! data; data; data; data; data; data; data; data; data; data
                            tim ? end
                          --}}}
                      --}}}
                      VAL INT total IS end MINUS start:
                      VAL INT ns IS INT ROUND (((REAL32 ROUND total) * 1000.0) / (REAL32 ROUND MEASURE.LOOPS)):
                      SEQ
                        C.trace.i ("                     Time taken (us): ", total)
                        C.trace.i ("                     Time per communication (ns): ", ns)
                        results[k][j] := ns
                --}}}
                --{{{  Output results for gnuplot
                SEQ i = 0 FOR SIZE LENGTHS
                  [NUM.TESTS + 1]INT data:
                  SEQ
                    data[0] := LENGTHS[i]
                    SEQ j = 0 FOR NUM.TESTS
                      data[j + 1] := results[j][i]
                    C.trace.results (data)
                --}}}
                C.trace ("bmpingpongtime: Slave done")
            ELSE
              STOP
          CHAN BOOL sync:
          PAR
            --{{{  Shutdown
            SEQ
              CLAIM net.handle
                pony.shutdown (net.handle)
              sync ! TRUE
            --}}}
            --{{{  Errors and shutdown of error-handler
            TIMER tim:
            INT t, result:
            MOBILE []PONY.ERROR err.array:
            SEQ
              tim ? t
              PRI ALT
                BOOL any:
                sync ? any
                  out.string ("Shutdown sync.*n", 0, err!)
                tim ? AFTER t PLUS 10000000
                  out.string ("Shutdown timeout.*n", 0, err!)
              out.string ("Getting errors after initial error-point.*n", 0, err!)
              INITIAL MOBILE []INT null.int.array IS MOBILE [0]INT:
              pony.err.get.errs.after (err.handle, err.point,
                                       TRUE, TRUE, TRUE, null.int.array,
                                       err.array, result)
              SEQ
                out.string ("Number of errors: ", 0, err!)
                out.int ((SIZE err.array), 0, err!)
                out.string ("*n", 0, err!)
                SEQ i = 0 FOR (SIZE err.array)
                  SEQ
                    out.string ("error: ans.concerned:         ", 0, err!)
                    out.bool (err.array[i][ans.concerned], 0, err!)
                    out.string ("*n       master.concerned:      ", 0, err!)
                    out.bool (err.array[i][master.concerned], 0, err!)
                    out.string ("*n       remote.node.concerned: ", 0, err!)
                    out.bool (err.array[i][remote.node.concerned], 0, err!)
                    out.string ("*n       remote.node.id:        ", 0, err!)
                    out.int (err.array[i][remote.node.id], 0, err!)
                    out.string ("*n       err.code:              ", 0, err!)
                    out.int (err.array[i][err.code], 0, err!)
                    out.string ("*n", 0, err!)
                out.string ("Shutting down error-handler.*n", 0, err!)
              pony.err.shutdown (err.handle)
              out.string ("Error-handler shutdown finished.*n", 0, err!)
            --}}}
      TRUE
        SKIP
    --{{{  Exit message
    out.string ("Finished! :)*n", 0, err!)
    --}}}
:

