Commits

Bryan O'Sullivan committed 6f98e8c

Split running a load test out from analysing it.

Comments (0)

Files changed (4)

 import Data.Text (pack)
 import Data.Text.Encoding (encodeUtf8)
 import Network.HTTP.LoadTest (NetworkError(..), Req(..))
+import Network.HTTP.LoadTest.Analysis (analyseBasic, analyseFull)
 import Network.HTTP.LoadTest.Report (reportBasic, reportEvents, reportFull)
 import Network.Socket (withSocketsDo)
 import System.Console.CmdArgs
     Right results -> do
       whenNormal $ T.print "analysing results\n" ()
       analysis <- if bootstrap
-                  then Right <$> LoadTest.analyseFull results
-                  else return . Left . LoadTest.analyseBasic $ results
+                  then Right <$> analyseFull results
+                  else return . Left . analyseBasic $ results
       let dump = object [ "config" .= cfg, "analysis" .= analysis ]
       case json of
         Just "-" -> L.putStrLn (encode dump)

lib/Network/HTTP/LoadTest.hs

     , Req(..)
     , defaultConfig
     , run
-    -- * Result analysis
-    , Analysis(..)
-    , Basic(..)
-    , analyseBasic
-    , analyseFull
     ) where
 
 import Control.Applicative ((<$>))
 import Control.Concurrent.Chan (newChan, readChan, writeChan)
 import Control.Exception (catch, throwIO, try)
 import Control.Monad (forM_, replicateM, when)
-import Criterion.Analysis (SampleAnalysis, analyseSample, scale)
 import Data.Either (partitionEithers)
-import Data.Function (on)
 import Data.List (nub)
 import Data.Time.Clock.POSIX (POSIXTime, getPOSIXTime)
 import Network.HTTP.Enumerator
 import Network.HTTP.LoadTest.Types
 import Prelude hiding (catch)
-import Statistics.Quantile (weightedAvg)
 import qualified Data.ByteString.Lazy as L
 import qualified Data.Vector as V
-import qualified Data.Vector.Algorithms.Intro as I
-import qualified Data.Vector.Generic as G
-import qualified Data.Vector.Unboxed as U
-import qualified Statistics.Sample as S
 import qualified System.Timeout as T
 
 run :: Config -> IO (Either [NetworkError] (V.Vector Summary))
       respCode = statusCode resp
     , respContentLength = fromIntegral . L.length . responseBody $ resp
     }
-
-analyseFull :: V.Vector Summary -> IO (Analysis SampleAnalysis)
-analyseFull sums = do
-  let sumv = sortBy (compare `on` summStart) sums
-      start = summStart . G.head $ sumv
-      end = summEnd . G.last $ sumv
-      elapsed = end - start
-      timeSlice = min elapsed 1 / 200
-      slices = U.unfoldrN (round (elapsed / timeSlice)) go (sumv,1)
-        where go (v,i) = let (a,b) = G.span (\s -> summStart s <= t) v
-                             t = start + (i * timeSlice)
-                         in Just (fromIntegral $ G.length a,(b,i+1))
-      ci = 0.95
-      resamples = 10 * 1000
-  l <- analyseSample ci (G.convert . G.map summElapsed $ sumv) resamples
-  t <- analyseSample ci slices resamples
-  return Analysis {
-                 latency = l
-               , latency99 = weightedAvg 99 100 . G.map summElapsed $ sumv
-               , latency999 = weightedAvg 999 1000 . G.map summElapsed $ sumv
-               , throughput = scale (recip timeSlice) t
-               , throughput10 = (/ timeSlice) . weightedAvg 10 100 $ slices
-    }
-
-analyseBasic :: V.Vector Summary -> Analysis Basic
-analyseBasic sums = Analysis {
-                      latency = Basic {
-                                  mean = S.mean . G.map summElapsed $ sums
-                                , stdDev = S.stdDev . G.map summElapsed $ sums
-                                }
-                    , latency99 = weightedAvg 99 100 . G.map summElapsed $ sums
-                    , latency999 = weightedAvg 999 1000 . G.map summElapsed $ sums
-                    , throughput = Basic {
-                                     mean = S.mean slices / timeSlice
-                                   , stdDev = S.stdDev slices / timeSlice
-                                   }
-                    , throughput10 = (/ timeSlice) . weightedAvg 10 100 $ slices
-                    }
- where sumv = sortBy (compare `on` summStart) sums
-       start = summStart . G.head $ sumv
-       end = summEnd . G.last $ sumv
-       elapsed = end - start
-       timeSlice = min elapsed 1 / 200
-       slices = U.unfoldrN (round (elapsed / timeSlice)) go (sumv,1)
-         where go (v,i) = let (a,b) = G.span (\s -> summStart s <= t) v
-                              t = start + (i * timeSlice)
-                          in Just (fromIntegral $ G.length a,(b,i+1))
-
--- | Sort a vector.
-sortBy :: (G.Vector v e) => I.Comparison e -> v e -> v e
-sortBy cmp = G.modify (I.sortBy cmp)
-{-# INLINE sortBy #-}

lib/Network/HTTP/LoadTest/Analysis.hs

+{-# LANGUAGE BangPatterns, RecordWildCards #-}
+
+module Network.HTTP.LoadTest.Analysis
+    (
+    -- * Result analysis
+      Analysis(..)
+    , Basic(..)
+    , analyseBasic
+    , analyseFull
+    ) where
+
+import Criterion.Analysis (SampleAnalysis, analyseSample, scale)
+import Data.Function (on)
+import Network.HTTP.LoadTest.Types (Analysis(..), Basic(..), Summary(..),
+                                    summEnd)
+import Prelude hiding (catch)
+import Statistics.Quantile (weightedAvg)
+import qualified Data.Vector as V
+import qualified Data.Vector.Algorithms.Intro as I
+import qualified Data.Vector.Generic as G
+import qualified Data.Vector.Unboxed as U
+import qualified Statistics.Sample as S
+
+analyseFull :: V.Vector Summary -> IO (Analysis SampleAnalysis)
+analyseFull sums = do
+  let sumv = sortBy (compare `on` summStart) sums
+      start = summStart . G.head $ sumv
+      end = summEnd . G.last $ sumv
+      elapsed = end - start
+      timeSlice = min elapsed 1 / 200
+      slices = U.unfoldrN (round (elapsed / timeSlice)) go (sumv,1)
+        where go (v,i) = let (a,b) = G.span (\s -> summStart s <= t) v
+                             t = start + (i * timeSlice)
+                         in Just (fromIntegral $ G.length a,(b,i+1))
+      ci = 0.95
+      resamples = 10 * 1000
+  l <- analyseSample ci (G.convert . G.map summElapsed $ sumv) resamples
+  t <- analyseSample ci slices resamples
+  return Analysis {
+                 latency = l
+               , latency99 = weightedAvg 99 100 . G.map summElapsed $ sumv
+               , latency999 = weightedAvg 999 1000 . G.map summElapsed $ sumv
+               , throughput = scale (recip timeSlice) t
+               , throughput10 = (/ timeSlice) . weightedAvg 10 100 $ slices
+    }
+
+analyseBasic :: V.Vector Summary -> Analysis Basic
+analyseBasic sums = Analysis {
+                      latency = Basic {
+                                  mean = S.mean . G.map summElapsed $ sums
+                                , stdDev = S.stdDev . G.map summElapsed $ sums
+                                }
+                    , latency99 = weightedAvg 99 100 . G.map summElapsed $ sums
+                    , latency999 = weightedAvg 999 1000 . G.map summElapsed $ sums
+                    , throughput = Basic {
+                                     mean = S.mean slices / timeSlice
+                                   , stdDev = S.stdDev slices / timeSlice
+                                   }
+                    , throughput10 = (/ timeSlice) . weightedAvg 10 100 $ slices
+                    }
+ where sumv = sortBy (compare `on` summStart) sums
+       start = summStart . G.head $ sumv
+       end = summEnd . G.last $ sumv
+       elapsed = end - start
+       timeSlice = min elapsed 1 / 200
+       slices = U.unfoldrN (round (elapsed / timeSlice)) go (sumv,1)
+         where go (v,i) = let (a,b) = G.span (\s -> summStart s <= t) v
+                              t = start + (i * timeSlice)
+                          in Just (fromIntegral $ G.length a,(b,i+1))
+
+-- | Sort a vector.
+sortBy :: (G.Vector v e) => I.Comparison e -> v e -> v e
+sortBy cmp = G.modify (I.sortBy cmp)
+{-# INLINE sortBy #-}
   hs-source-dirs: lib
   exposed-modules:
     Network.HTTP.LoadTest
+    Network.HTTP.LoadTest.Analysis
     Network.HTTP.LoadTest.Report
     Network.HTTP.LoadTest.Types
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.