git.iko.soy/distributed-process
on master help sign in
Modify the benchmarks to output the latencies

This enables us to plot them.

commit39d80854dc1087fa6b6ff458cc6967f60c8990f1 authorEdsko de Vries <edsko@well-typed.com> dateWed 11 Apr 2012, 13:07 (15 years ago) parentcb07733
4 files changed+99−72
benchmarks/Makefile+4−1 benchmarks/PingTCP.hs+32−35 benchmarks/PingTCPTransport.hs+36−36 benchmarks/pingtest.c+27
benchmarks/Makefile+4−1
@@ -8,6 +8,9 @@ trials = 1
88# Disable this to test installed packages only:
99INCLUDES= -i../network-transport/src -i../network-transport-pipes/src
1010
11+# Enable for profiling
12+PROFILING=-prof -fprof-auto
13+
1114ifeq ($(GHC),)
1215 GHC=ghc
1316endif
@@ -16,7 +19,7 @@ BENCHS= PingTCP.exe PingTCPTransport.exe PingPipes.exe SendTransport.exe
1619
1720all: $(BENCHS)
1821$(BENCHS): %.exe: %.hs
19− $(GHC) -O2 -rtsopts -threaded --make $(INCLUDES) $< -o $@
22+ $(GHC) -O2 -rtsopts -threaded --make $(INCLUDES) $(PROFILING) $< -o $@
2023
2124#-------------------------------------------------------------------------------
2225# Shorthands for running benchmarks:
benchmarks/PingTCP.hs+32−35
@@ -1,10 +1,8 @@
1−{-# LANGUAGE CPP #-}
1+{-# LANGUAGE CPP, BangPatterns #-}
22
33module Main where
44
55import Control.Monad
6−import Criterion.Main (Benchmark, bench, defaultMainWith, nfIO)
7−import Criterion.Config (defaultConfig, ljust, Config(cfgSamples))
86
97import Data.Int
108import qualified Data.Serialize as Ser
@@ -16,6 +14,8 @@ import Network.Socket
1614 , defaultHints
1715 , getAddrInfo, listen, setSocketOption, socket, sClose, withSocketsDo )
1816import System.Environment (getArgs, withArgs)
17+import Data.Time (getCurrentTime, diffUTCTime, NominalDiffTime)
18+import System.IO (withFile, IOMode(..), hPutStrLn)
1919
2020import qualified Network.Socket as N
2121
@@ -23,11 +23,13 @@ import Debug.Trace
2323
2424#ifndef LAZY
2525import Data.ByteString (ByteString)
26+import Data.ByteString.Char8 (pack)
27+import qualified Data.ByteString as BS
2628import qualified Network.Socket.ByteString as NBS
2729encode = Ser.encode
2830decode = Ser.decode
2931#else
30−import Data.ByteString.Lazy (ByteString)
32+import Data.ByteString.Lazy (ByteString, pack)
3133import qualified Network.Socket.ByteString.Lazy as NBS
3234encode = Ser.encodeLazy
3335decode = Ser.decodeLazy
@@ -72,9 +74,9 @@ main = do
7274 (clientSock, clientAddr) <- accept sock
7375
7476 putStrLn "server: listening for pings"
75− forever (pong clientSock)
77+ pong clientSock
7678
77− "client": host : service : pingsStr : reps : args' -> withSocketsDo $ do
79+ "client": host : service : pingsStr : [] -> withSocketsDo $ do
7880 let pings = read pingsStr
7981 serverAddrs <- getAddrInfo
8082 Nothing
@@ -85,36 +87,31 @@ main = do
8587
8688 N.connect sock (addrAddress serverAddr)
8789
88− -- benchmark the pings
89− case (read reps) :: Int of
90− 0 -> error "What would zero reps mean?"
91− 1 -> do putStrLn "Because you're timing only one trial, skipping Criterion..."
92− replicateM_ pings (ping sock)
93− n -> withArgs args' $ defaultMainWith
94− (defaultConfig{ cfgSamples = ljust n })
95− (return ()) -- Init action.
96− [ benchPing sock (fromIntegral pings) ]
97− putStrLn "Done with all ping/pongs."
98−
99−-- withArgs args' $ defaultMain [ benchPing sock pings ]
100−-- replicateM_ pings (ping sock)
101−
102−-- | Each `ping` sends a single byte, and expects to receive one
103−-- back in return.
104−ping :: Socket -> IO Int64
105−ping sock = do
106− NBS.send sock $ encode (42 :: Int64)
107− bs <- NBS.recv sock 8
108− either error return $ decode bs
90+ ping sock pings
91+
92+pingMessage :: ByteString
93+pingMessage = pack "ping123"
94+
95+ping :: Socket -> Int -> IO ()
96+ping sock pings = go [] pings
97+ where
98+ go :: [Double] -> Int -> IO ()
99+ go rtl 0 = do
100+ withFile "round-trip-latency-tcp.data" WriteMode $ \h ->
101+ forM_ (zip [0..] rtl) $ \(i, latency) ->
102+ hPutStrLn h $ (show i) ++ " " ++ (show latency)
103+ putStrLn $ "client did " ++ show pings ++ " pings"
104+ go rtl !i = do
105+ before <- getCurrentTime
106+ NBS.send sock pingMessage
107+ bs <- NBS.recv sock 8
108+ after <- getCurrentTime
109+ let latency = (1e6 :: Double) * realToFrac (diffUTCTime after before)
110+ latency `seq` go (latency : rtl) (i - 1)
109111
110112pong :: Socket -> IO ()
111113pong sock = do
112114 bs <- NBS.recv sock 8
113− NBS.sendAll sock bs
114− return ()
115−
116−benchPing :: Socket -> Int64 -> Benchmark
117−benchPing sock n =
118− bench "PingTCP" $
119− nfIO (replicateM_ (fromIntegral n) (ping sock))
120−
115+ when (BS.length bs > 0) $ do
116+ NBS.sendAll sock bs
117+ pong sock
benchmarks/PingTCPTransport.hs+36−36
@@ -1,4 +1,4 @@
1−{-# LANGUAGE CPP #-}
1+{-# LANGUAGE CPP, BangPatterns #-}
22
33module Main where
44
@@ -6,14 +6,14 @@ import Network.Transport (newConnection, receive, connect, send, defaultHints,
66 serialize, deserialize, SourceEnd, TargetEnd)
77import Network.Transport.TCP (mkTransport, TCPConfig (..))
88
9−import Control.Monad (forever, replicateM_)
10−import Criterion.Main (Benchmark, bench, defaultMainWith, nfIO)
11−import Criterion.Config (defaultConfig, ljust, Config(cfgSamples))
9+import Control.Monad (forever, replicateM_, forM_)
1210
1311import qualified Data.Serialize as Ser
1412import Data.Maybe (fromJust)
1513import Data.Int
1614import System.Environment (getArgs, withArgs)
15+import Data.Time (getCurrentTime, diffUTCTime)
16+import System.IO (withFile, IOMode(..), hPutStrLn)
1717
1818#ifndef LAZY
1919import qualified Data.ByteString.Char8 as BS
@@ -68,10 +68,10 @@ main = do
6868
6969 -- always respond to a ping with a pong
7070 putStrLn "server: awaiting pings"
71− forever $ pong targetEndPing sourceEndPong
71+ pong targetEndPing sourceEndPong
7272
7373
74− "client" : host : service : sourceAddrFilePath : pingsStr : reps : args' -> do
74+ "client" : host : service : sourceAddrFilePath : pingsStr : [] -> do
7575 let pings = read pingsStr
7676 -- establish transport
7777 transport <- mkTransport $ TCPConfig defaultHints host service
@@ -84,39 +84,39 @@ main = do
8484 (sourceAddrPong, targetEndPong) <- newConnection transport
8585 send sourceEndPing [serialize sourceAddrPong]
8686
87− -- benchmark the pings
88− case (read reps) :: Int of
89− 0 -> error "What would zero reps mean?"
90− 1 -> do putStrLn "Because you're timing only one trial, skipping Criterion..."
91− replicateM_ pings (ping sourceEndPing targetEndPong 42)
92− n -> withArgs args' $ defaultMainWith
93− (defaultConfig{ cfgSamples = ljust n })
94− (return ()) -- Init action.
95− [ benchPing sourceEndPing targetEndPong (fromIntegral pings)]
87+ ping sourceEndPing targetEndPong pings
9688 putStrLn "Done with all ping/pongs."
9789
98−-- | This function takes a `TargetEnd` for the pings, and a `SourceEnd` for
99−-- pongs. Whenever a ping is received from the `TargetEnd`, a pong is sent
100−-- in reply down the `SourceEnd`, repeating whatever was sent.
90+-- | The message we use to ping (CAF so that we don't keep encoding it)
91+pingMessage :: BS.ByteString
92+pingMessage = BS.pack "ping123"
93+
94+-- | Keep replying to pings (send pongs)
10195pong :: TargetEnd -> SourceEnd -> IO ()
10296pong targetEndPing sourceEndPong = do
10397 bs <- receive targetEndPing
10498 send sourceEndPong bs
105−
106−-- | The effect of `ping sourceEndPing targetEndPong n` is to send the number
107−-- `n` using `sourceEndPing`, and to then receive the a number from
108−-- `targetEndPong`, which is then returned.
109−ping :: SourceEnd -> TargetEnd -> Int64 -> IO Int64
110−ping sourceEndPing targetEndPong n = do
111− send sourceEndPing [encode n]
112− [bs] <- receive targetEndPong
113− let (Right n) = decode bs
114− return $! n
115−
116−-- | The effect of `benchPing sourceEndPing targetEndPong n` is to send
117−-- `n` pings down `sourceEndPing` using the `ping` function. The time
118−-- taken is benchmarked.
119−benchPing :: SourceEnd -> TargetEnd -> Int64 -> Benchmark
120−benchPing sourceEndPing targetEndPong n = bench "PingTransport" $
121− nfIO (replicateM_ (fromIntegral n) (ping sourceEndPing targetEndPong 42))
122−
99+ pong targetEndPing sourceEndPong
100+
101+-- | Send a number of pings
102+ping :: SourceEnd -> TargetEnd -> Int -> IO ()
103+ping sourceEndPing targetEndPong pings = go [] pings
104+ where
105+ go :: [Double] -> Int -> IO ()
106+ go rtl 0 = do
107+ outputData rtl
108+ putStrLn $ "client did " ++ show pings ++ " pings"
109+ go rtl !i = do
110+ before <- getCurrentTime
111+ send sourceEndPing [pingMessage]
112+ [bs] <- receive targetEndPong
113+ after <- getCurrentTime
114+ let latency = (1e6 :: Double) * realToFrac (diffUTCTime after before)
115+ latency `seq` go (latency : rtl) (i - 1)
116+
117+-- | Output latencies to a file to be plotted
118+outputData :: [Double] -> IO ()
119+outputData rtl = do
120+ withFile "round-trip-latency-tcp-transport.data" WriteMode $ \h ->
121+ forM_ (zip [0..] rtl) $ \(i, latency) ->
122+ hPutStrLn h $ (show i) ++ " " ++ (show latency)
benchmarks/pingtest.c+27
@@ -1,3 +1,23 @@
1+/**
2+ * Compute baseline average and standard deviancy ping latency
3+ *
4+ * Compile using
5+ *
6+ * gcc -o pingtest -O2 -std=c99 pingtest.c
7+ *
8+ * Then start server
9+ *
10+ * ./pingtest server &
11+ *
12+ * And finally start the client
13+ *
14+ * ./pingtest client <number of pings; for instance, 10000>
15+ *
16+ * The server will terminate when the client does.
17+ *
18+ * Edsko de Vries <edsko@well-typed.com>
19+ */
20+
121#include <stdio.h>
222#include <stdlib.h>
323#include <sys/types.h>
@@ -112,6 +132,13 @@ int client(int pings) {
112132
113133 printf("client did %d pings\n", pings);
114134
135+ // Write data to a file for plotting
136+ FILE* data = fopen("round-trip-latency-c.data", "wt");
137+ for(int i = 0; i < pings; i++) {
138+ fprintf(data, "%i %lf\n", i, round_trip_latency[i]);
139+ }
140+ fclose(data);
141+
115142 // compute average
116143 double round_trip_latency_average = 0;
117144 for(int i = 0; i < pings; i++) {