git.iko.soy/distributed-process
on master help sign in
Compare one socket pair with two
commita366d5e48fa5e71fdca3614f22daf5f792045a6b authorEdsko de Vries <edsko@well-typed.com> dateSat 14 Apr 2012, 09:30 (15 years ago) parentc7f72ce
5 files changed+219−90
benchmarks/Indirection.gnuplot+2 benchmarks/JustPingThroughChan.hs+33−45 benchmarks/JustPingThroughMVar.hs+34−45 benchmarks/JustPingTwoSocketPairs.hs+149 benchmarks/Makefile.JustPing+1
benchmarks/Indirection.gnuplot+2
@@ -3,10 +3,12 @@ set yrange [0:150]
33plot "JustPingWithHeader.data" smooth bezier with lines title "JustPingWithHeader", \
44 "JustPingThroughChan.data" smooth bezier with lines title "JustPingThroughChan", \
55 "JustPingThroughMVar.data" smooth bezier with lines title "JustPingThroughMVar", \
6+ "JustPingTwoSocketPairs.data" smooth bezier with lines title "JustPingTwoSocketPairs", \
67 "JustPingTransport.data" smooth bezier with lines title "JustPingTransport"
78set terminal postscript color
89set output "Indirection.ps"
910plot "JustPingWithHeader.data" smooth bezier with lines title "JustPingWithHeader", \
1011 "JustPingThroughChan.data" smooth bezier with lines title "JustPingThroughChan", \
1112 "JustPingThroughMVar.data" smooth bezier with lines title "JustPingThroughMVar", \
13+ "JustPingTwoSocketPairs.data" smooth bezier with lines title "JustPingTwoSocketPairs", \
1214 "JustPingTransport.data" smooth bezier with lines title "JustPingTransport"
benchmarks/JustPingThroughChan.hs+33−45
@@ -6,7 +6,7 @@ import Control.Monad
66
77import Data.Int
88import Network.Socket
9− ( AddrInfoFlag (AI_PASSIVE), HostName, ServiceName, Socket
9+ ( AddrInfo, AddrInfoFlag (AI_PASSIVE), HostName, ServiceName, Socket
1010 , SocketType (Stream), SocketOption (ReuseAddr)
1111 , accept, addrAddress, addrFlags, addrFamily, bindSocket, defaultProtocol
1212 , defaultHints
@@ -32,7 +32,9 @@ import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan)
3232foreign import ccall unsafe "htonl" htonl :: CInt -> CInt
3333foreign import ccall unsafe "ntohl" ntohl :: CInt -> CInt
3434
35−main :: IO ()
35+passive :: Maybe AddrInfo
36+passive = Just (defaultHints { addrFlags = [AI_PASSIVE] })
37+
3638main = do
3739 [pingsStr] <- getArgs
3840 serverReady <- newEmptyMVar
@@ -40,50 +42,44 @@ main = do
4042
4143 -- Start the server
4244 forkIO $ do
43− putStrLn "server: creating TCP connection"
44− serverAddrs <- getAddrInfo
45− (Just (defaultHints { addrFlags = [AI_PASSIVE] } ))
46− Nothing
47− (Just "8080")
48− let serverAddr = head serverAddrs
49− sock <- socket (addrFamily serverAddr) Stream defaultProtocol
45+ -- Initialize the server
46+ serverAddr:_ <- getAddrInfo passive Nothing (Just "8080")
47+ sock <- socket (addrFamily serverAddr) Stream defaultProtocol
5048 setSocketOption sock ReuseAddr 1
5149 bindSocket sock (addrAddress serverAddr)
52−
53− putStrLn "server: awaiting client connection"
54− putMVar serverReady ()
5550 listen sock 1
56− (clientSock, clientAddr) <- accept sock
5751
58− -- Set up channel that we will listen on and echo to the client
59− chan <- newChan
60− forkIO $ forever $ do
61− msg <- readChan chan
62− send clientSock msg
52+ -- Set up multiplexing channel
53+ multiplexChannel <- newChan
6354
64− -- Read from the client and output on the channel
65− putStrLn "server: listening for pings"
66− pong clientSock chan
55+ -- Wait for incoming connections (pings from the client)
56+ putMVar serverReady ()
57+ (clientSock, pingAddr) <- accept sock
58+ forkIO $ socketToChan clientSock multiplexChannel
59+
60+ -- Reply to the client
61+ forever $ readChan multiplexChannel >>= send clientSock
6762
6863 -- Start the client
6964 forkIO $ do
7065 takeMVar serverReady
71− let pings = read pingsStr
72− serverAddrs <- getAddrInfo
73− Nothing
74− (Just "127.0.0.1")
75− (Just "8080")
76− let serverAddr = head serverAddrs
77− sock <- socket (addrFamily serverAddr) Stream defaultProtocol
78−
79− N.connect sock (addrAddress serverAddr)
80−
81− ping sock pings
66+ serverAddr:_ <- getAddrInfo Nothing (Just "127.0.0.1") (Just "8080")
67+ clientSock <- socket (addrFamily serverAddr) Stream defaultProtocol
68+ N.connect clientSock (addrAddress serverAddr)
69+ ping clientSock (read pingsStr)
8270 putMVar clientDone ()
8371
8472 -- Wait for the client to finish
8573 takeMVar clientDone
8674
75+socketToChan :: Socket -> Chan ByteString -> IO ()
76+socketToChan sock chan = go
77+ where
78+ go = do bs <- recv sock
79+ when (BS.length bs > 0) $ do
80+ writeChan chan bs
81+ go
82+
8783pingMessage :: ByteString
8884pingMessage = pack "ping123"
8985
@@ -96,29 +92,21 @@ ping sock pings = go pings
9692 go !i = do
9793 before <- getCurrentTime
9894 send sock pingMessage
99− bs <- recv sock 8
95+ bs <- recv sock
10096 after <- getCurrentTime
10197 -- putStrLn $ "client received " ++ unpack bs
10298 let latency = (1e6 :: Double) * realToFrac (diffUTCTime after before)
10399 hPutStrLn stderr $ show i ++ " " ++ show latency
104100 go (i - 1)
105101
106−pong :: Socket -> Chan ByteString -> IO ()
107−pong sock chan = do
108− bs <- recv sock 8
109− -- putStrLn $ "server received " ++ unpack bs
110− when (BS.length bs > 0) $ do
111− writeChan chan bs
112− pong sock chan
113−
114−-- | Wrapper around NBS.recv (for profiling)
115−recv :: Socket -> Int -> IO ByteString
116−recv sock _ = do
102+-- | Receive a package
103+recv :: Socket -> IO ByteString
104+recv sock = do
117105 header <- NBS.recv sock 4
118106 length <- decodeLength header
119107 NBS.recv sock (fromIntegral (length :: Int32))
120108
121−-- | Wrapper around NBS.send (for profiling)
109+-- | Send a package
122110send :: Socket -> ByteString -> IO ()
123111send sock bs = do
124112 length <- encodeLength (fromIntegral (BS.length bs))
benchmarks/JustPingThroughMVar.hs+34−45
@@ -6,7 +6,7 @@ import Control.Monad
66
77import Data.Int
88import Network.Socket
9− ( AddrInfoFlag (AI_PASSIVE), HostName, ServiceName, Socket
9+ ( AddrInfo, AddrInfoFlag (AI_PASSIVE), HostName, ServiceName, Socket
1010 , SocketType (Stream), SocketOption (ReuseAddr)
1111 , accept, addrAddress, addrFlags, addrFamily, bindSocket, defaultProtocol
1212 , defaultHints
@@ -27,11 +27,14 @@ import Data.ByteString.Internal as BSI
2727import Foreign.Storable (pokeByteOff, peekByteOff)
2828import Foreign.C (CInt(..))
2929import Foreign.ForeignPtr (withForeignPtr)
30+import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan)
3031
3132foreign import ccall unsafe "htonl" htonl :: CInt -> CInt
3233foreign import ccall unsafe "ntohl" ntohl :: CInt -> CInt
3334
34−main :: IO ()
35+passive :: Maybe AddrInfo
36+passive = Just (defaultHints { addrFlags = [AI_PASSIVE] })
37+
3538main = do
3639 [pingsStr] <- getArgs
3740 serverReady <- newEmptyMVar
@@ -39,50 +42,44 @@ main = do
3942
4043 -- Start the server
4144 forkIO $ do
42− putStrLn "server: creating TCP connection"
43− serverAddrs <- getAddrInfo
44− (Just (defaultHints { addrFlags = [AI_PASSIVE] } ))
45− Nothing
46− (Just "8080")
47− let serverAddr = head serverAddrs
48− sock <- socket (addrFamily serverAddr) Stream defaultProtocol
45+ -- Initialize the server
46+ serverAddr:_ <- getAddrInfo passive Nothing (Just "8080")
47+ sock <- socket (addrFamily serverAddr) Stream defaultProtocol
4948 setSocketOption sock ReuseAddr 1
5049 bindSocket sock (addrAddress serverAddr)
51−
52− putStrLn "server: awaiting client connection"
53− putMVar serverReady ()
5450 listen sock 1
55− (clientSock, clientAddr) <- accept sock
5651
57− -- Set up an mvar that we will listen on and echo to the client
58− mvar <- newEmptyMVar
59− forkIO $ forever $ do
60− msg <- takeMVar mvar
61− send clientSock msg
52+ -- Set up multiplexing channel
53+ multiplexMVar <- newEmptyMVar
6254
63− -- Read from the client and output on the channel
64− putStrLn "server: listening for pings"
65− pong clientSock mvar
55+ -- Wait for incoming connections (pings from the client)
56+ putMVar serverReady ()
57+ (clientSock, pingAddr) <- accept sock
58+ forkIO $ socketToMVar clientSock multiplexMVar
59+
60+ -- Reply to the client
61+ forever $ takeMVar multiplexMVar >>= send clientSock
6662
6763 -- Start the client
6864 forkIO $ do
6965 takeMVar serverReady
70− let pings = read pingsStr
71− serverAddrs <- getAddrInfo
72− Nothing
73− (Just "127.0.0.1")
74− (Just "8080")
75− let serverAddr = head serverAddrs
76− sock <- socket (addrFamily serverAddr) Stream defaultProtocol
77−
78− N.connect sock (addrAddress serverAddr)
79−
80− ping sock pings
66+ serverAddr:_ <- getAddrInfo Nothing (Just "127.0.0.1") (Just "8080")
67+ clientSock <- socket (addrFamily serverAddr) Stream defaultProtocol
68+ N.connect clientSock (addrAddress serverAddr)
69+ ping clientSock (read pingsStr)
8170 putMVar clientDone ()
8271
8372 -- Wait for the client to finish
8473 takeMVar clientDone
8574
75+socketToMVar :: Socket -> MVar ByteString -> IO ()
76+socketToMVar sock mvar = go
77+ where
78+ go = do bs <- recv sock
79+ when (BS.length bs > 0) $ do
80+ putMVar mvar bs
81+ go
82+
8683pingMessage :: ByteString
8784pingMessage = pack "ping123"
8885
@@ -95,29 +92,21 @@ ping sock pings = go pings
9592 go !i = do
9693 before <- getCurrentTime
9794 send sock pingMessage
98− bs <- recv sock 8
95+ bs <- recv sock
9996 after <- getCurrentTime
10097 -- putStrLn $ "client received " ++ unpack bs
10198 let latency = (1e6 :: Double) * realToFrac (diffUTCTime after before)
10299 hPutStrLn stderr $ show i ++ " " ++ show latency
103100 go (i - 1)
104101
105−pong :: Socket -> MVar ByteString -> IO ()
106−pong sock mvar = do
107− bs <- recv sock 8
108− -- putStrLn $ "server received " ++ unpack bs
109− when (BS.length bs > 0) $ do
110− putMVar mvar bs
111− pong sock mvar
112−
113−-- | Wrapper around NBS.recv (for profiling)
114−recv :: Socket -> Int -> IO ByteString
115−recv sock _ = do
102+-- | Receive a package
103+recv :: Socket -> IO ByteString
104+recv sock = do
116105 header <- NBS.recv sock 4
117106 length <- decodeLength header
118107 NBS.recv sock (fromIntegral (length :: Int32))
119108
120−-- | Wrapper around NBS.send (for profiling)
109+-- | Send a package
121110send :: Socket -> ByteString -> IO ()
122111send sock bs = do
123112 length <- encodeLength (fromIntegral (BS.length bs))
benchmarks/JustPingTwoSocketPairs.hsnew file+149
@@ -0,0 +1,149 @@
1+{-# LANGUAGE CPP, BangPatterns #-}
2+
3+module Main where
4+
5+import Control.Monad
6+
7+import Data.Int
8+import Network.Socket
9+ ( AddrInfo, AddrInfoFlag (AI_PASSIVE), HostName, ServiceName, Socket
10+ , SocketType (Stream), SocketOption (ReuseAddr)
11+ , accept, addrAddress, addrFlags, addrFamily, bindSocket, defaultProtocol
12+ , defaultHints
13+ , getAddrInfo, listen, setSocketOption, socket, sClose, withSocketsDo )
14+import System.Environment (getArgs, withArgs)
15+import Data.Time (getCurrentTime, diffUTCTime, NominalDiffTime)
16+import System.IO (withFile, IOMode(..), hPutStrLn, Handle, stderr)
17+import Control.Concurrent (forkIO)
18+import Control.Concurrent.MVar (newEmptyMVar, takeMVar, putMVar)
19+import qualified Network.Socket as N
20+import Debug.Trace
21+import Data.ByteString (ByteString)
22+import Data.ByteString.Char8 (pack, unpack)
23+import qualified Data.ByteString as BS
24+import qualified Network.Socket.ByteString as NBS
25+import Data.Time (getCurrentTime, diffUTCTime, NominalDiffTime)
26+import Data.ByteString.Internal as BSI
27+import Foreign.Storable (pokeByteOff, peekByteOff)
28+import Foreign.C (CInt(..))
29+import Foreign.ForeignPtr (withForeignPtr)
30+import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan)
31+
32+foreign import ccall unsafe "htonl" htonl :: CInt -> CInt
33+foreign import ccall unsafe "ntohl" ntohl :: CInt -> CInt
34+
35+passive :: Maybe AddrInfo
36+passive = Just (defaultHints { addrFlags = [AI_PASSIVE] })
37+
38+main = do
39+ [pingsStr] <- getArgs
40+ serverReady <- newEmptyMVar
41+ clientReady <- newEmptyMVar
42+ clientDone <- newEmptyMVar
43+
44+ -- Start the server
45+ forkIO $ do
46+ -- Initialize the server
47+ serverAddr:_ <- getAddrInfo passive Nothing (Just "8080")
48+ sock <- socket (addrFamily serverAddr) Stream defaultProtocol
49+ setSocketOption sock ReuseAddr 1
50+ bindSocket sock (addrAddress serverAddr)
51+ listen sock 1
52+
53+ -- Set up multiplexing channel
54+ multiplexChannel <- newChan
55+
56+ -- Connect to the client (to reply)
57+ forkIO $ do
58+ takeMVar clientReady
59+ clientAddr:_ <- getAddrInfo Nothing (Just "127.0.0.1") (Just "8081")
60+ pongSock <- socket (addrFamily clientAddr) Stream defaultProtocol
61+ N.connect pongSock (addrAddress clientAddr)
62+ forever $ readChan multiplexChannel >>= send pongSock
63+
64+ -- Wait for incoming connections (pings from the client)
65+ putMVar serverReady ()
66+ (pingSock, pingAddr) <- accept sock
67+ socketToChan pingSock multiplexChannel
68+
69+ -- Start the client
70+ forkIO $ do
71+ clientAddr:_ <- getAddrInfo passive Nothing (Just "8081")
72+ sock <- socket (addrFamily clientAddr) Stream defaultProtocol
73+ setSocketOption sock ReuseAddr 1
74+ bindSocket sock (addrAddress clientAddr)
75+ listen sock 1
76+
77+ -- Set up multiplexing channel
78+ multiplexChannel <- newChan
79+
80+ -- Connect to the server (to send pings)
81+ forkIO $ do
82+ takeMVar serverReady
83+ serverAddr:_ <- getAddrInfo Nothing (Just "127.0.0.1") (Just "8080")
84+ pingSock <- socket (addrFamily serverAddr) Stream defaultProtocol
85+ N.connect pingSock (addrAddress serverAddr)
86+ ping pingSock multiplexChannel (read pingsStr)
87+ putMVar clientDone ()
88+
89+ -- Wait for incoming connections (pongs from the server)
90+ putMVar clientReady ()
91+ (pongSock, pongAddr) <- accept sock
92+ socketToChan pongSock multiplexChannel
93+
94+ -- Wait for the client to finish
95+ takeMVar clientDone
96+
97+socketToChan :: Socket -> Chan ByteString -> IO ()
98+socketToChan sock chan = go
99+ where
100+ go = do bs <- recv sock
101+ when (BS.length bs > 0) $ do
102+ writeChan chan bs
103+ go
104+
105+pingMessage :: ByteString
106+pingMessage = pack "ping123"
107+
108+ping :: Socket -> Chan ByteString -> Int -> IO ()
109+ping sock chan pings = go pings
110+ where
111+ go :: Int -> IO ()
112+ go 0 = do
113+ putStrLn $ "client did " ++ show pings ++ " pings"
114+ go !i = do
115+ before <- getCurrentTime
116+ send sock pingMessage
117+ bs <- readChan chan
118+ after <- getCurrentTime
119+ -- putStrLn $ "client received " ++ unpack bs
120+ let latency = (1e6 :: Double) * realToFrac (diffUTCTime after before)
121+ hPutStrLn stderr $ show i ++ " " ++ show latency
122+ go (i - 1)
123+
124+-- | Receive a package
125+recv :: Socket -> IO ByteString
126+recv sock = do
127+ header <- NBS.recv sock 4
128+ length <- decodeLength header
129+ NBS.recv sock (fromIntegral (length :: Int32))
130+
131+-- | Send a package
132+send :: Socket -> ByteString -> IO ()
133+send sock bs = do
134+ length <- encodeLength (fromIntegral (BS.length bs))
135+ NBS.sendMany sock [length, bs]
136+
137+-- | Encode length (manual for now)
138+encodeLength :: Int32 -> IO ByteString
139+encodeLength i32 =
140+ BSI.create 4 $ \p ->
141+ pokeByteOff p 0 (htonl (fromIntegral i32))
142+
143+-- | Decode length (manual for now)
144+decodeLength :: ByteString -> IO Int32
145+decodeLength bs =
146+ let (fp, _, _) = BSI.toForeignPtr bs in
147+ withForeignPtr fp $ \p -> do
148+ w32 <- peekByteOff p 0
149+ return (fromIntegral (ntohl w32))
benchmarks/Makefile.JustPing+1
@@ -6,6 +6,7 @@ INCLUDES=-i../network-transport/src -i../network-transport-pipes/src
66Indirection.ps: JustPingWithHeader.data \
77 JustPingThroughChan.data \
88 JustPingThroughMVar.data \
9+ JustPingTwoSocketPairs.data \
910 JustPingTransport.data
1011 gnuplot ./Indirection.gnuplot
1112