roguestar-gl-0.4.0.0: src/Statistics.hs
module Statistics
(Statistics,newStatistics,runStatistics)
where
import qualified Data.Vector.Unboxed as V
import Statistics.Sample as S
import Data.List as L
import Statistics.Quantile
import Control.Concurrent
import RSAGL.FRP.Time
import System.IO
import System.IO.Unsafe
import RSAGL.Math.AbstractVector
import Control.Monad
import RSAGL.Types
import Text.Printf
import Control.Exception
{-# NOINLINE error_pump #-}
error_pump :: Chan String
error_pump = unsafePerformIO $
do pump <- newChan
_ <- forkIO $ forever $
do hPutStrLn stderr =<< readChan pump
return pump
data Statistics = Statistics {
statistics_sample :: MVar [Double],
statistics_max :: MVar Double,
statistics_avg :: MVar Double,
statistics_time :: MVar Time, -- time since last flushing of statistics
statistics_name :: String }
newStatistics :: String -> IO Statistics
newStatistics name =
do sample <- newMVar []
t <- newMVar =<< getTime
s_max <- newMVar 0
s_avg <- newMVar 1000
return $ Statistics {
statistics_sample = sample,
statistics_max = s_max,
statistics_avg = s_avg,
statistics_time = t,
statistics_name = name }
runStatistics :: Statistics -> IO a -> IO a
runStatistics stats action =
do t_start <- getTime
a <- action
t_end <- getTime
let t_diff = f2f $ toSeconds $ t_end `sub` t_start
modifyMVar_ (statistics_sample stats) $ return . (t_diff :)
modifyMVar_ (statistics_max stats) $ return . (max t_diff)
modifyMVar_ (statistics_avg stats) $ return . (\t -> (99*t + t_diff)/100)
_ <- evaluate =<< readMVar (statistics_max stats)
_ <- evaluate =<< readMVar (statistics_avg stats)
modifyMVar_ (statistics_time stats) $ \t ->
do let should_report = (toSeconds (t_end `sub` t) > 30)
when should_report $ liftM (const ()) $ forkIO $
do modifyMVar_ (statistics_sample stats) $ \x ->
do let sv = V.fromList $ take (60*30) x :: Sample
let f = printf "%.4f" . (*60) :: Double -> String
writeChan error_pump $ "\nSTATISTICS " ++ statistics_name stats ++
"\nMEAN " ++ f (mean sv) ++
"\nSTD DEV " ++ f (stdDev sv) ++
"\nKURTOSIS " ++ f (kurtosis sv) ++
"\nQUARTILES " ++ (concat $ intersperse " | " $ map f $
[continuousBy medianUnbiased 0 4 sv,
continuousBy medianUnbiased 1 4 sv,
continuousBy medianUnbiased 2 4 sv,
continuousBy medianUnbiased 3 4 sv,
continuousBy medianUnbiased 4 4 sv])
writeChan error_pump =<< liftM ((statistics_name stats ++ " lifetime maximum ") ++) (liftM f $ readMVar $ statistics_max stats)
writeChan error_pump =<< liftM ((statistics_name stats ++ " floating average ") ++) (liftM f $ readMVar $ statistics_avg stats)
return []
return $ if should_report then t_end else t
return a