--
--	commstime.occ -- context-switch/communication benchmark
--	Copyright (C) P.H.Welch and D.C.Wood  <{phw,dcw}@ukc.ac.uk>
--	Modifications (C) 2002 Fred Barnes  <frmb2@ukc.ac.uk>
--
--	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., 675 Mass Ave, Cambridge, MA 02139, USA.
--

--{{{  includes, uses
#INCLUDE "udc.module"
#INCLUDE "course.module"
--}}}  

--{{{  PROC comms.time (CHAN OF BYTE keyboard, screen, error)
PROC comms.time (CHAN OF BYTE keyboard, screen, error)

  --{{{  PROC seq.delta (CHAN OF INT in, out.0, out.1)
  PROC seq.delta (CHAN OF INT in, out.0, out.1)
    WHILE TRUE
      INT n:
      SEQ
        in ? n
        out.0 ! n
        out.1 ! n
  :
  --}}}

  --{{{  PROC consume (VAL INT n.loops, CHAN OF INT in, CHAN OF BYTE out)
  PROC consume (VAL INT n.loops, CHAN OF INT in, CHAN OF BYTE out)
    TIMER tim:
    INT t0, t1:
    INT value:
    SEQ
      --{{{  warm-up loop
      VAL INT warm.up IS 16:
      SEQ i = 0 FOR warm.up
        in ? value
      --}}}
      WHILE TRUE
        SEQ
          tim ? t0
          --{{{  bench-mark loop
          SEQ i = 0 FOR n.loops
            in ? value
          --}}}
          tim ? t1
          --{{{  report
          VAL INT microsecs IS t1 MINUS t0:
          VAL INT64 nanosecs IS 1000 * (INT64 microsecs):
          SEQ
            out.string ("Last value received = ", 0, out)
            out.int (value, 0, out)
            out.string ("*c*n", 0, out)
            out.string ("Time = ", 0, out)
            out.int (microsecs, 0, out)
            out.string (" microsecs*c*n", 0, out)
            out.string ("Time per loop = ", 0, out)
            out.int (INT (nanosecs/(INT64 n.loops)), 0, out)
            out.string (" nanosecs*c*n", 0, out)
            out.string ("Context switch = ", 0, out)
            out.int (INT ((nanosecs/(INT64 n.loops))/4), 0, out)
            out.string (" nanosecs*c*n*n", 0, out)
          --}}}
  :
  --}}}

  --{{{  some local PROCs, until I rebuild the course library with udc support
  PROC delta (CHAN INT in?, out.0!, out.1!)
    WHILE TRUE
      INT v:
      SEQ
        in ? v
        PAR
          out.0 ! v
          out.1 ! v
  :

  PROC prefix (VAL INT n, CHAN INT in?, out!)
    INITIAL INT v IS n:
    WHILE TRUE
      SEQ
        out ! v
        in ? v
  :

  PROC succ (CHAN INT in?, out!)
    WHILE TRUE
      INT x:
      SEQ
        in ? x
        out ! x
  :
  --}}}  

  BOOL use.seq.delta:
  BOOL use.buf.chan:
  INT uaddr0, uaddr1, uaddr2, uaddr3:

  SEQ

    --{{{  announce
    SEQ
      out.string ("*c*nCommstime in occam, user-defined channels version ...*c*n*n", 0, screen)
      out.string ("Using the SEQ-output version of the delta process*c*n", 0, screen)
      out.string ("yields a more accurate measure of context-switch time*c*n*n", 0, screen)
      out.string ("Using the PAR-output version carries an extra overhead*c*n", 0, screen)
      out.string ("of one process startup/shutdown per Commstime loop*c*n*n", 0, screen)
      out.string ("By comparing **loop** times between the SEQ and PAR versions,*c*n", 0, screen)
      out.string ("the process startup/shutdown overhead may be deduced*c*n*n", 0, screen)
    --}}}

    --{{{  SEQ delta ?
    ask.bool ("Sequential delta? ", use.seq.delta, keyboard, screen)
    --}}}  
    --{{{  buffered channel ?
    ask.bool ("Use buffered channels? ", use.buf.chan, keyboard, screen)
    --}}}  
    out.string ("*nCommstime starting ...*c*n*n", 0, screen)

    --{{{  allocate "external" channels
    IF
      use.buf.chan
        INT buf.size:
        SEQ
          ask.int ("Buffer size? ", buf.size, 4, keyboard, screen)
          udc.bufchan.alloc (buf.size, uaddr0)
          udc.bufchan.alloc (buf.size, uaddr1)
          udc.bufchan.alloc (buf.size, uaddr2)
          udc.bufchan.alloc (buf.size, uaddr3)
      TRUE
        SEQ
          udc.softchan.alloc (uaddr0)
          udc.softchan.alloc (uaddr1)
          udc.softchan.alloc (uaddr2)
          udc.softchan.alloc (uaddr3)
    --}}}  
    --{{{  network
    PLACED CHAN INT a uaddr0:
    PLACED CHAN INT b uaddr1:
    PLACED CHAN INT c uaddr2:
    PLACED CHAN INT d uaddr3:
    PAR
      prefix (0, b, a)
      IF
        use.seq.delta
          seq.delta (a, c, d)    -- the one defined above
        TRUE
          delta (a, c, d)        -- the one that does a parallel output
      succ (c, b)
      consume (1000000, d, screen)
    --}}}  
:
--}}}

