on master help sign in
Show latency stats in diagnostics mode
9617a71Harendra Kumar
src/Streamly/SVar.hs+99−30
@@ -20,6 +20,10 @@
20-- Portability : GHC
20-- Portability : GHC
21--
21--
22--
22--
23+#ifdef DIAGNOSTICS_VERBOSE
24+#define DIAGNOSTICS
25+#endif
26+
23module Streamly.SVar
27module Streamly.SVar
24 (
28 (
25 MonadAsync
29 MonadAsync
@@ -80,8 +84,9 @@ module Streamly.SVar
80 , delThread
84 , delThread
81
85
82 , toStreamVar
86 , toStreamVar
83−#ifdef DIAGNOSTICS
84 , SVarStats (..)
87 , SVarStats (..)
88+ , NanoSecs (..)
89+#ifdef DIAGNOSTICS
85 , dumpSVar
90 , dumpSVar
86#endif
91#endif
87 )
92 )
@@ -127,7 +132,6 @@ import Control.Concurrent.MVar (tryTakeMVar)
127import Control.Exception
132import Control.Exception
128 (catches, throwIO, Handler(..), BlockedIndefinitelyOnMVar(..),
133 (catches, throwIO, Handler(..), BlockedIndefinitelyOnMVar(..),
129 BlockedIndefinitelyOnSTM(..))
134 BlockedIndefinitelyOnSTM(..))
130−import Data.Maybe (isJust)
131import System.IO (hPutStrLn, stderr)
135import System.IO (hPutStrLn, stderr)
132#endif
136#endif
133
137
@@ -264,18 +268,17 @@ data YieldRateInfo = YieldRateInfo
264 , workerStopTimeStamp :: IORef TimeSpec
268 , workerStopTimeStamp :: IORef TimeSpec
265 }
269 }
266
270
267−#ifdef DIAGNOSTICS
268data SVarStats = SVarStats {
271data SVarStats = SVarStats {
269− totalDispatches :: IORef Int
272+ totalDispatches :: IORef Int
270− , maxWorkers :: IORef Int
273+ , maxWorkers :: IORef Int
271− , maxOutQSize :: IORef Int
274+ , maxOutQSize :: IORef Int
272− , maxHeapSize :: IORef Int
275+ , maxHeapSize :: IORef Int
273− , maxWorkQSize :: IORef Int
276+ , maxWorkQSize :: IORef Int
277+ , avgWorkerLatency :: IORef (Count, NanoSecs)
274− -- , avgLatency :: IORef NanoSecs
278+ , minWorkerLatency :: IORef NanoSecs
275− -- , minLatency :: IORef NanoSecs
279+ , maxWorkerLatency :: IORef NanoSecs
276− -- , maxLatency :: IORef NanoSecs
280+ , svarStopTime :: IORef (Maybe TimeSpec)
277}
281}
278−#endif
279
282
280data Limit = Unlimited | Limited Word deriving Show
283data Limit = Unlimited | Limited Word deriving Show
281
284
@@ -308,13 +311,13 @@ data SVar t m a = SVar
308 , accountThread :: ThreadId -> m ()
311 , accountThread :: ThreadId -> m ()
309 , workerStopMVar :: MVar ()
312 , workerStopMVar :: MVar ()
310
313
314+ , svarStats :: SVarStats
311#ifdef DIAGNOSTICS
315#ifdef DIAGNOSTICS
312 -- to track garbage collection of SVar
316 -- to track garbage collection of SVar
313 , svarRef :: Maybe (IORef ())
317 , svarRef :: Maybe (IORef ())
314 , outputHeap :: IORef (Heap (Entry Int (AheadHeapEntry t m a)) , Int)
318 , outputHeap :: IORef (Heap (Entry Int (AheadHeapEntry t m a)) , Int)
315 -- Shared work queue (stream, seqNo)
319 -- Shared work queue (stream, seqNo)
316 , aheadWorkQueue :: IORef ([t m a], Int)
320 , aheadWorkQueue :: IORef ([t m a], Int)
317− , svarStats :: SVarStats
318#endif
321#endif
319 }
322 }
320
323
@@ -456,20 +459,58 @@ getStreamLatency = _streamLatency
456-------------------------------------------------------------------------------
459-------------------------------------------------------------------------------
457
460
458#ifdef DIAGNOSTICS
461#ifdef DIAGNOSTICS
459−dumpSVarStats :: SVarStats -> SVarStyle -> Bool -> IO String
462+dumpSVarStats :: SVar t m a -> SVarStats -> SVarStyle -> IO String
460−dumpSVarStats ss style _paced = do
463+dumpSVarStats sv ss style = do
464+ case yieldRateInfo sv of
465+ Nothing -> return ()
466+ Just yinfo -> do
467+ _ <- liftIO $ collectLatency (svarStats sv) yinfo
468+ return ()
469+
461 dispatches <- readIORef $ totalDispatches ss
470 dispatches <- readIORef $ totalDispatches ss
462 maxWrk <- readIORef $ maxWorkers ss
471 maxWrk <- readIORef $ maxWorkers ss
463 maxOq <- readIORef $ maxOutQSize ss
472 maxOq <- readIORef $ maxOutQSize ss
464 maxHp <- readIORef $ maxHeapSize ss
473 maxHp <- readIORef $ maxHeapSize ss
474+ minLat <- readIORef $ minWorkerLatency ss
475+ maxLat <- readIORef $ maxWorkerLatency ss
476+ (avgCnt, avgTime) <- readIORef $ avgWorkerLatency ss
477+ svarLat <- case yieldRateInfo sv of
478+ Nothing -> return 0
479+ Just yinfo -> do
480+ (cnt, startTime) <- readIORef $ workerLongTermLatency yinfo
481+ if cnt > 0
482+ then do
483+ t <- readIORef (svarStopTime ss)
484+ case t of
485+ Nothing -> do
486+ now <- getTime Monotonic
487+ let interval = toNanoSecs (now - startTime)
488+ return $ interval `div` fromIntegral cnt
489+ Just stopTime -> do
490+ let interval = toNanoSecs (stopTime - startTime)
491+ return $ interval `div` fromIntegral cnt
492+ else return 0
465
493
466 return $ unlines
494 return $ unlines
467 [ "total dispatches = " ++ show dispatches
495 [ "total dispatches = " ++ show dispatches
468 , "max workers = " ++ show maxWrk
496 , "max workers = " ++ show maxWrk
469 , "max outQSize = " ++ show maxOq
497 , "max outQSize = " ++ show maxOq
470− , if style == AheadVar
498+ ++ (if style == AheadVar
471− then "heap max size = " ++ show maxHp
499+ then "\nheap max size = " ++ show maxHp
500+ else "")
501+ ++ (if minLat > 0
502+ then "\nmin worker latency = " ++ show minLat
503+ else "")
504+ ++ (if maxLat > 0
505+ then "\nmax worker latency = " ++ show maxLat
506+ else "")
507+ ++ (if avgCnt > 0
508+ then "\navg worker latency = "
509+ ++ show (avgTime `div` fromIntegral avgCnt)
472− else ""
510+ else "")
511+ ++ (if svarLat > 0
512+ then "\nSVar latency = " ++ show svarLat
513+ else "")
473 ]
514 ]
474
515
475{-# NOINLINE dumpSVar #-}
516{-# NOINLINE dumpSVar #-}
@@ -498,8 +539,7 @@ dumpSVar sv = do
498 else return False
539 else return False
499 rthread <- readIORef $ workerThreads sv
540 rthread <- readIORef $ workerThreads sv
500 workers <- readIORef $ workerCount sv
541 workers <- readIORef $ workerCount sv
501− stats <- dumpSVarStats (svarStats sv) (svarStyle sv)
542+ stats <- dumpSVarStats sv (svarStats sv) (svarStyle sv)
502− (isJust (yieldRateInfo sv))
503
543
504 return $ unlines
544 return $ unlines
505 [ "tid = " ++ show tid
545 [ "tid = " ++ show tid
@@ -630,6 +670,9 @@ incrementYieldLimit sv =
630-- TBD Each worker can have their own queue and the consumer can empty one
670-- TBD Each worker can have their own queue and the consumer can empty one
631-- queue at a time, that way contention can be reduced.
671-- queue at a time, that way contention can be reduced.
632
672
673+-- XXX Only yields should be counted in the buffer limit and not the Stop
674+-- events.
675+
633-- | This function is used by the producer threads to queue output for the
676-- | This function is used by the producer threads to queue output for the
634-- consumer thread to consume. Returns whether the queue has more space.
677-- consumer thread to consume. Returns whether the queue has more space.
635send :: SVar t m a -> ChildEvent a -> IO Bool
678send :: SVar t m a -> ChildEvent a -> IO Bool
@@ -1126,7 +1169,7 @@ countDispatchWorkers workerLimit count duration wLatency expectedLat =
1126 -- XXX we can have a maxEfficiency combinator as well which runs the
1169 -- XXX we can have a maxEfficiency combinator as well which runs the
1127 -- producer at the maximal efficiency i.e. the number of workers are chosen
1170 -- producer at the maximal efficiency i.e. the number of workers are chosen
1128 -- such that the latency is minimum or within a range. Or we can call it
1171 -- such that the latency is minimum or within a range. Or we can call it
1129− -- maxLatency.
1172+ -- maxWorkerLatency.
1130 --
1173 --
1131 let nWorkers = (fromIntegral wLatency) / (fromIntegral expectedLat)
1174 let nWorkers = (fromIntegral wLatency) / (fromIntegral expectedLat)
1132 -- Calculate how many yields are we ahead or behind to match the exact
1175 -- Calculate how many yields are we ahead or behind to match the exact
@@ -1207,8 +1250,8 @@ useCollectedBatch yinfo latency colRef measRef = do
1207-- period. The former two are used for accurate measurement of the going rate
1250-- period. The former two are used for accurate measurement of the going rate
1208-- whereas the average is used for future estimates e.g. how many workers
1251-- whereas the average is used for future estimates e.g. how many workers
1209-- should be maintained to maintain the rate.
1252-- should be maintained to maintain the rate.
1210−collectLatency :: YieldRateInfo -> IO (Count, TimeSpec, NanoSecs)
1253+collectLatency :: SVarStats -> YieldRateInfo -> IO (Count, TimeSpec, NanoSecs)
1211−collectLatency yinfo = do
1254+collectLatency _ss yinfo = do
1212 let cur = workerCurrentLatency yinfo
1255 let cur = workerCurrentLatency yinfo
1213 col = workerCollectedLatency yinfo
1256 col = workerCollectedLatency yinfo
1214 longTerm = workerLongTermLatency yinfo
1257 longTerm = workerLongTermLatency yinfo
@@ -1228,6 +1271,14 @@ collectLatency yinfo = do
1228 if (pendingCount > 0)
1271 if (pendingCount > 0)
1229 then do
1272 then do
1230 let new = pendingTime `div` (fromIntegral pendingCount)
1273 let new = pendingTime `div` (fromIntegral pendingCount)
1274+#ifdef DIAGNOSTICS
1275+ minLat <- readIORef (minWorkerLatency _ss)
1276+ when (new < minLat || minLat == 0) $
1277+ writeIORef (minWorkerLatency _ss) new
1278+
1279+ maxLat <- readIORef (maxWorkerLatency _ss)
1280+ when (new > maxLat) $ writeIORef (maxWorkerLatency _ss) new
1281+#endif
1231 -- To avoid minor fluctuations update in batches
1282 -- To avoid minor fluctuations update in batches
1232 if (pendingCount > fromIntegral magicMaxBuffer)
1283 if (pendingCount > fromIntegral magicMaxBuffer)
1233 || (pendingTime > minThreadDelay)
1284 || (pendingTime > minThreadDelay)
@@ -1236,6 +1287,10 @@ collectLatency yinfo = do
1236 || (prev == 0)
1287 || (prev == 0)
1237 then do
1288 then do
1238 useCollectedBatch yinfo new col measured
1289 useCollectedBatch yinfo new col measured
1290+#ifdef DIAGNOSTICS
1291+ modifyIORef (avgWorkerLatency _ss) $
1292+ \(cnt, t) -> (cnt + pendingCount, t + pendingTime)
1293+#endif
1239 modifyIORef longTerm $ \(_, t) -> (lcount', t)
1294 modifyIORef longTerm $ \(_, t) -> (lcount', t)
1240 return (lcount', ltime, new)
1295 return (lcount', ltime, new)
1241 else do
1296 else do
@@ -1263,7 +1318,7 @@ dispatchWorkerPaced :: MonadAsync m => SVar t m a -> m Bool
1263dispatchWorkerPaced sv = do
1318dispatchWorkerPaced sv = do
1264 let workerLimit = maxWorkerLimit sv
1319 let workerLimit = maxWorkerLimit sv
1265 let yinfo = fromJust $ yieldRateInfo sv
1320 let yinfo = fromJust $ yieldRateInfo sv
1266− (count, tstamp, wLatency) <- liftIO $ collectLatency yinfo
1321+ (count, tstamp, wLatency) <- liftIO $ collectLatency (svarStats sv) yinfo
1267 -- XXX use workerBootstrapLatency
1322 -- XXX use workerBootstrapLatency
1268 if wLatency == 0
1323 if wLatency == 0
1269 -- Need to measure the latency with a single worker before we can perform
1324 -- Need to measure the latency with a single worker before we can perform
@@ -1547,13 +1602,15 @@ getAheadSVar st f = do
1547 Just x -> Just <$> newIORef x
1602 Just x -> Just <$> newIORef x
1548 rateInfo <- getYieldRateInfo st
1603 rateInfo <- getYieldRateInfo st
1549
1604
1550−#ifdef DIAGNOSTICS
1551 disp <- newIORef 0
1605 disp <- newIORef 0
1552 maxWrk <- newIORef 0
1606 maxWrk <- newIORef 0
1553 maxOq <- newIORef 0
1607 maxOq <- newIORef 0
1554 maxHs <- newIORef 0
1608 maxHs <- newIORef 0
1555 maxWq <- newIORef 0
1609 maxWq <- newIORef 0
1556−#endif
1610+ avgLat <- newIORef (0, NanoSecs 0)
1611+ maxLat <- newIORef (NanoSecs 0)
1612+ minLat <- newIORef (NanoSecs 0)
1613+ stpTime <- newIORef Nothing
1557
1614
1558 let getSVar sv readOutput postProc = SVar
1615 let getSVar sv readOutput postProc = SVar
1559 { outputQueue = outQ
1616 { outputQueue = outQ
@@ -1577,14 +1634,18 @@ getAheadSVar st f = do
1577 , svarRef = Nothing
1634 , svarRef = Nothing
1578 , aheadWorkQueue = q
1635 , aheadWorkQueue = q
1579 , outputHeap = outH
1636 , outputHeap = outH
1637+#endif
1580 , svarStats = SVarStats
1638 , svarStats = SVarStats
1581 { totalDispatches = disp
1639 { totalDispatches = disp
1582 , maxWorkers = maxWrk
1640 , maxWorkers = maxWrk
1583 , maxOutQSize = maxOq
1641 , maxOutQSize = maxOq
1584 , maxHeapSize = maxHs
1642 , maxHeapSize = maxHs
1585 , maxWorkQSize = maxWq
1643 , maxWorkQSize = maxWq
1644+ , avgWorkerLatency = avgLat
1645+ , minWorkerLatency = minLat
1646+ , maxWorkerLatency = maxLat
1647+ , svarStopTime = stpTime
1586 }
1648 }
1587−#endif
1588 }
1649 }
1589
1650
1590 let sv =
1651 let sv =
@@ -1622,13 +1683,17 @@ getParallelSVar = do
1622 outQMv <- newEmptyMVar
1683 outQMv <- newEmptyMVar
1623 active <- newIORef 0
1684 active <- newIORef 0
1624 running <- newIORef S.empty
1685 running <- newIORef S.empty
1625−#ifdef DIAGNOSTICS
1686+
1626 disp <- newIORef 0
1687 disp <- newIORef 0
1627 maxWrk <- newIORef 0
1688 maxWrk <- newIORef 0
1628 maxOq <- newIORef 0
1689 maxOq <- newIORef 0
1629 maxHs <- newIORef 0
1690 maxHs <- newIORef 0
1630 maxWq <- newIORef 0
1691 maxWq <- newIORef 0
1631−#endif
1692+ avgLat <- newIORef (0, NanoSecs 0)
1693+ maxLat <- newIORef (NanoSecs 0)
1694+ minLat <- newIORef (NanoSecs 0)
1695+ stpTime <- newIORef Nothing
1696+
1632 let sv =
1697 let sv =
1633 SVar { outputQueue = outQ
1698 SVar { outputQueue = outQ
1634 , remainingYields = Nothing
1699 , remainingYields = Nothing
@@ -1651,14 +1716,18 @@ getParallelSVar = do
1651 , svarRef = Nothing
1716 , svarRef = Nothing
1652 , aheadWorkQueue = undefined
1717 , aheadWorkQueue = undefined
1653 , outputHeap = undefined
1718 , outputHeap = undefined
1719+#endif
1654 , svarStats = SVarStats
1720 , svarStats = SVarStats
1655 { totalDispatches = disp
1721 { totalDispatches = disp
1656 , maxWorkers = maxWrk
1722 , maxWorkers = maxWrk
1657 , maxOutQSize = maxOq
1723 , maxOutQSize = maxOq
1658 , maxHeapSize = maxHs
1724 , maxHeapSize = maxHs
1659 , maxWorkQSize = maxWq
1725 , maxWorkQSize = maxWq
1726+ , avgWorkerLatency = avgLat
1727+ , minWorkerLatency = minLat
1728+ , maxWorkerLatency = maxLat
1729+ , svarStopTime = stpTime
1660 }
1730 }
1661−#endif
1662 }
1731 }
1663 in return sv
1732 in return sv
1664
1733
src/Streamly/Streams/Ahead.hs+4
@@ -8,6 +8,10 @@
8{-# LANGUAGE StandaloneDeriving #-}
8{-# LANGUAGE StandaloneDeriving #-}
9{-# LANGUAGE UndecidableInstances #-} -- XXX
9{-# LANGUAGE UndecidableInstances #-} -- XXX
10
10
11+#ifdef DIAGNOSTICS_VERBOSE
12+#define DIAGNOSTICS
13+#endif
14+
11-- |
15-- |
12-- Module : Streamly.Streams.Ahead
16-- Module : Streamly.Streams.Ahead
13-- Copyright : (c) 2017 Harendra Kumar
17-- Copyright : (c) 2017 Harendra Kumar
src/Streamly/Streams/Async.hs+23−6
@@ -9,6 +9,10 @@
9{-# LANGUAGE StandaloneDeriving #-}
9{-# LANGUAGE StandaloneDeriving #-}
10{-# LANGUAGE UndecidableInstances #-} -- XXX
10{-# LANGUAGE UndecidableInstances #-} -- XXX
11
11
12+#ifdef DIAGNOSTICS_VERBOSE
13+#define DIAGNOSTICS
14+#endif
15+
12-- |
16-- |
13-- Module : Streamly.Streams.Async
17-- Module : Streamly.Streams.Async
14-- Copyright : (c) 2017 Harendra Kumar
18-- Copyright : (c) 2017 Harendra Kumar
@@ -259,13 +263,16 @@ getLifoSVar st = do
259 Just x -> Just <$> newIORef x
263 Just x -> Just <$> newIORef x
260 rateInfo <- getYieldRateInfo st
264 rateInfo <- getYieldRateInfo st
261
265
262−#ifdef DIAGNOSTICS
263 disp <- newIORef 0
266 disp <- newIORef 0
264 maxWrk <- newIORef 0
267 maxWrk <- newIORef 0
265 maxOq <- newIORef 0
268 maxOq <- newIORef 0
266 maxHs <- newIORef 0
269 maxHs <- newIORef 0
267 maxWq <- newIORef 0
270 maxWq <- newIORef 0
268−#endif
271+ avgLat <- newIORef (0, NanoSecs 0)
272+ maxLat <- newIORef (NanoSecs 0)
273+ minLat <- newIORef (NanoSecs 0)
274+ stpTime <- newIORef Nothing
275+
269 let isWorkFinished _ = null <$> readIORef q
276 let isWorkFinished _ = null <$> readIORef q
270
277
271 let isWorkFinishedLimited sv = do
278 let isWorkFinishedLimited sv = do
@@ -300,14 +307,18 @@ getLifoSVar st = do
300 , svarRef = Nothing
307 , svarRef = Nothing
301 , aheadWorkQueue = undefined
308 , aheadWorkQueue = undefined
302 , outputHeap = undefined
309 , outputHeap = undefined
310+#endif
303 , svarStats = SVarStats
311 , svarStats = SVarStats
304 { totalDispatches = disp
312 { totalDispatches = disp
305 , maxWorkers = maxWrk
313 , maxWorkers = maxWrk
306 , maxOutQSize = maxOq
314 , maxOutQSize = maxOq
307 , maxHeapSize = maxHs
315 , maxHeapSize = maxHs
308 , maxWorkQSize = maxWq
316 , maxWorkQSize = maxWq
317+ , avgWorkerLatency = avgLat
318+ , minWorkerLatency = minLat
319+ , maxWorkerLatency = maxLat
320+ , svarStopTime = stpTime
309 }
321 }
310−#endif
311 }
322 }
312
323
313 let sv =
324 let sv =
@@ -347,13 +358,15 @@ getFifoSVar st = do
347 Just x -> Just <$> newIORef x
358 Just x -> Just <$> newIORef x
348 rateInfo <- getYieldRateInfo st
359 rateInfo <- getYieldRateInfo st
349
360
350−#ifdef DIAGNOSTICS
351 disp <- newIORef 0
361 disp <- newIORef 0
352 maxWrk <- newIORef 0
362 maxWrk <- newIORef 0
353 maxOq <- newIORef 0
363 maxOq <- newIORef 0
354 maxHs <- newIORef 0
364 maxHs <- newIORef 0
355 maxWq <- newIORef 0
365 maxWq <- newIORef 0
356−#endif
366+ avgLat <- newIORef (0, NanoSecs 0)
367+ maxLat <- newIORef (NanoSecs 0)
368+ minLat <- newIORef (NanoSecs 0)
369+ stpTime <- newIORef Nothing
357
370
358 let isWorkFinished _ = nullQ q
371 let isWorkFinished _ = nullQ q
359 let isWorkFinishedLimited sv = do
372 let isWorkFinishedLimited sv = do
@@ -388,14 +401,18 @@ getFifoSVar st = do
388 , svarRef = Nothing
401 , svarRef = Nothing
389 , aheadWorkQueue = undefined
402 , aheadWorkQueue = undefined
390 , outputHeap = undefined
403 , outputHeap = undefined
404+#endif
391 , svarStats = SVarStats
405 , svarStats = SVarStats
392 { totalDispatches = disp
406 { totalDispatches = disp
393 , maxWorkers = maxWrk
407 , maxWorkers = maxWrk
394 , maxOutQSize = maxOq
408 , maxOutQSize = maxOq
395 , maxHeapSize = maxHs
409 , maxHeapSize = maxHs
396 , maxWorkQSize = maxWq
410 , maxWorkQSize = maxWq
411+ , avgWorkerLatency = avgLat
412+ , minWorkerLatency = minLat
413+ , maxWorkerLatency = maxLat
414+ , svarStopTime = stpTime
397 }
415 }
398−#endif
399 }
416 }
400
417
401 let sv =
418 let sv =
src/Streamly/Streams/SVar.hs+8−1
@@ -11,6 +11,10 @@
11
11
12#include "inline.h"
12#include "inline.h"
13
13
14+#ifdef DIAGNOSTICS_VERBOSE
15+#define DIAGNOSTICS
16+#endif
17+
14-- |
18-- |
15-- Module : Streamly.Streams.SVar
19-- Module : Streamly.Streams.SVar
16-- Copyright : (c) 2017 Harendra Kumar
20-- Copyright : (c) 2017 Harendra Kumar
@@ -36,8 +40,9 @@ import Control.Monad.Catch (throwM)
36import Data.Int (Int64)
40import Data.Int (Int64)
37#ifdef DIAGNOSTICS
41#ifdef DIAGNOSTICS
38import Control.Monad.IO.Class (liftIO)
42import Control.Monad.IO.Class (liftIO)
39−import Data.IORef (newIORef, mkWeakIORef)
43+import Data.IORef (newIORef, writeIORef, mkWeakIORef)
40import System.IO (hPutStrLn, stderr)
44import System.IO (hPutStrLn, stderr)
45+import System.Clock (Clock(Monotonic), getTime)
41#endif
46#endif
42
47
43import Streamly.SVar
48import Streamly.SVar
@@ -72,6 +77,8 @@ fromStreamVar sv = Stream $ \st stp sng yld -> do
72
77
73 allDone stp = do
78 allDone stp = do
74#ifdef DIAGNOSTICS
79#ifdef DIAGNOSTICS
80+ t <- liftIO $ getTime Monotonic
81+ liftIO $ writeIORef (svarStopTime (svarStats sv)) (Just t)
75#ifdef DIAGNOSTICS_VERBOSE
82#ifdef DIAGNOSTICS_VERBOSE
76 liftIO $ printSVar sv "SVar Done"
83 liftIO $ printSVar sv "SVar Done"
77#endif
84#endif