| 1 | {-# OPTIONS_GHC -O2 #-} |
|---|
| 2 | import IO |
|---|
| 3 | import System.Environment |
|---|
| 4 | import System.CPUTime |
|---|
| 5 | import Text.Printf |
|---|
| 6 | import Control.Monad |
|---|
| 7 | import Control.Concurrent |
|---|
| 8 | import Control.Concurrent.MVar |
|---|
| 9 | |
|---|
| 10 | type Msg = (Int, String) |
|---|
| 11 | |
|---|
| 12 | nthreadsDefault :: Int |
|---|
| 13 | nthreadsDefault = 10000 |
|---|
| 14 | |
|---|
| 15 | npumpDefault :: Int |
|---|
| 16 | npumpDefault = 100 |
|---|
| 17 | |
|---|
| 18 | main :: IO () |
|---|
| 19 | main = do |
|---|
| 20 | hSetBuffering stdout NoBuffering |
|---|
| 21 | args <- getArgs |
|---|
| 22 | let (nthreads, npump) = |
|---|
| 23 | case args of |
|---|
| 24 | [] -> (nthreadsDefault, npumpDefault) |
|---|
| 25 | [arg] -> (read arg, npumpDefault) |
|---|
| 26 | [arg1,arg2] -> (read arg1, read arg2) |
|---|
| 27 | _ -> error "Use 0, 1, or 2 arguments\n" |
|---|
| 28 | printf "Creating pipeline with %d processes in it.\n" nthreads |
|---|
| 29 | t1s <- getCPUTimeDouble |
|---|
| 30 | s <- newEmptyMVar |
|---|
| 31 | e <- createMany nthreads s |
|---|
| 32 | t1e <- getCPUTimeDouble |
|---|
| 33 | printf "Pumping a single message through the pipeline.\n" |
|---|
| 34 | t2s <- getCPUTimeDouble |
|---|
| 35 | pump 1 s e "Hello, World!" |
|---|
| 36 | t2e <- getCPUTimeDouble |
|---|
| 37 | printf "Pumping a %d messages through the pipeline.\n" npump |
|---|
| 38 | t3s <- getCPUTimeDouble |
|---|
| 39 | pump npump s e "x" |
|---|
| 40 | t3e <- getCPUTimeDouble |
|---|
| 41 | let ct = t1e - t1s |
|---|
| 42 | p1 = t2e - t2s |
|---|
| 43 | p2 = t3e - t3s |
|---|
| 44 | n = fromIntegral nthreads * 1e-6 |
|---|
| 45 | p = fromIntegral npump |
|---|
| 46 | printf " n create pump1 pump2 create/n pump1/n pump2/n\n" |
|---|
| 47 | printf " s s s us us us\n" |
|---|
| 48 | printf "%8d %8.3f %8.3f %8.3f %8.2f %8.2f %8.2f\n" nthreads ct p1 p2 (ct/n) (p1/n) (p2/n/p) |
|---|
| 49 | |
|---|
| 50 | pump :: Int -> MVar Msg -> MVar Msg -> String -> IO () |
|---|
| 51 | pump n s e t = do |
|---|
| 52 | forkIO $ replicateM_ n $ putMVar s (0, t) |
|---|
| 53 | replicateM_ n $ do |
|---|
| 54 | msg <- takeMVar e |
|---|
| 55 | when (t /= snd msg) $ |
|---|
| 56 | error "Distorted message" |
|---|
| 57 | |
|---|
| 58 | createMany :: Int -> MVar Msg -> IO (MVar Msg) |
|---|
| 59 | createMany 0 v = return v |
|---|
| 60 | createMany n v = do |
|---|
| 61 | o <- newEmptyMVar |
|---|
| 62 | forkIO $ copy v o |
|---|
| 63 | createMany (n-1) o |
|---|
| 64 | |
|---|
| 65 | copy :: MVar Msg -> MVar Msg -> IO () |
|---|
| 66 | copy i o = do |
|---|
| 67 | (n, v) <- takeMVar i |
|---|
| 68 | let n' = n+1 |
|---|
| 69 | seq n' (putMVar o (n', v)) |
|---|
| 70 | copy i o |
|---|
| 71 | |
|---|
| 72 | getCPUTimeDouble :: IO Double |
|---|
| 73 | getCPUTimeDouble = do |
|---|
| 74 | t <- getCPUTime |
|---|
| 75 | return $ fromInteger t * 1e-12 |
|---|