[Shootout-list] ring of processes
Aaron Denney
wnoise@ofb.net
Sat, 2 Oct 2004 11:30:04 -0600
--LQksG6bCIzRHxTLp
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
I have a first draft of this in Haskell. It wasn't clear from the
description exactly what the master process is supposed to after sending
the first two messages off, and I don't fully understand what the erlang
versions do, so I've had it replicate what the slave processes do:
relay 10 high-priority messages, then 1 low priority messages, 10 times.
Could someone verify this is what it should be doing? Any other
comments?
--
Aaron Denney
-><-
--LQksG6bCIzRHxTLp
Content-Type: text/plain; charset=us-ascii
Content-Description: ringmsg.hs
Content-Disposition: attachment; filename="ringmsg.hs"
{-
- ringmsg.hs
- http://shootout.alioth.debian.org/bench/ringmsg/
-
- There is no generalized message sending between Haskell threads, each
- bit of data has to have someplace to go. This is implemented by
- hooking up "channels" (Chan a) between all of the processes, telling
- each where to send, and where to receive. In this light, the "check
- sender" is a bit silly. MVars could also work for this case. They
- might be lighter weight. This is currently taking 2.5 seconds per
- iteration on my machine, so it bears investigation.
-
- A closer match to what Erlang does would be to only have one channel,
- but stick a priority queue type thing (plus filtered access & removal)
- on it.
-
- The Erlang implementation only checks for the low priority messages
- every 10 high priority messages, it looks like the "after 0" clause
- means it doesn't block for it. We do. This may change somethings.
-}
module Main(main) where
import Control.Concurrent
import System(getArgs)
import List(zipWith4)
-- Constants
hiloratio = 10 -- how many high priority messages to send per low priority.
processes = 8192 -- how many processes to put in a ring.
fork = forkIO -- forkOS would be the other choice.
forever :: IO () -> IO ()
forever x = sequence_ $ repeat x
for :: Int -> IO () -> IO ()
for count x = sequence_ $ replicate count x
type ID = Int
data Message a = M ID a
assert :: Bool -> IO ()
assert False = error "assert failed"
assert True = return ()
slavestep (sendid, loin, hiin) (myid, loout, hiout) = do
for hiloratio $ sendhis sendid myid hiin hiout
sendlos sendid myid loin loout
slaveproc a b = forever $ slavestep a b
masterproc runs a@(lastid, loin, hiin) b@(myid, loout, hiout) = do
starthis myid hiout
startlos myid loout
for runs $ slavestep a b
sendhis sendid myid hiin hiout = do
M s d <- readChan hiin
assert $ sendid == s
writeChan hiout (M myid d)
sendlos = sendhis
starthis myid hiout = do
writeChan hiout (M myid ())
startlos = starthis
main = do ~[runs] <- getArgs
doit $ read runs
doit :: Int -> IO ()
doit runs = do
let ids = [1..processes]
hichans <- sequence $ replicate processes newChan
lochans <- sequence $ replicate processes newChan
let args = zip3 ids hichans lochans
let slaveprocs = zipWith slaveproc args (tail args)
mapM fork slaveprocs
masterproc runs (last args) (head args)
--LQksG6bCIzRHxTLp--