From 34edd618b075e493d5174bde6e0d57b082c751ec Mon Sep 17 00:00:00 2001 From: Harendra Kumar Date: Sat, 12 Jan 2019 02:15:28 +0530 Subject: [PATCH] Move time formatting routines in the Time module --- src/Streamly/SVar.hs | 40 +++------------------- src/Streamly/Time/Units.hs | 68 +++++++++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 36 deletions(-) diff --git a/src/Streamly/SVar.hs b/src/Streamly/SVar.hs index 62ee4c171..f8e1927e4 100644 --- a/src/Streamly/SVar.hs +++ b/src/Streamly/SVar.hs @@ -134,9 +134,8 @@ import GHC.IO (IO(..)) import Streamly.Time.Clock (Clock(..), getTime) import Streamly.Time.Units (AbsTime, NanoSecond64(..), MicroSecond64(..), diffAbsTime64, - fromRelTime64, toRelTime64) + fromRelTime64, toRelTime64, showNanoSecond64, showRelTime64) import System.IO (hPutStrLn, stderr) -import Text.Printf (printf) import qualified Data.Heap as H import qualified Data.Set as S @@ -643,31 +642,6 @@ collectLatency sv yinfo drain = do -- Dumping the SVar for debug/diag ------------------------------------------------------------------------------- --- | Convert a number of seconds to a string. The string will consist --- of four decimal places, followed by a short description of the time --- units. -secs :: Double -> String -secs k - | k < 0 = '-' : secs (-k) - | k >= 1 = k `with` "s" - | k >= 1e-3 = (k*1e3) `with` "ms" -#ifdef mingw32_HOST_OS - | k >= 1e-6 = (k*1e6) `with` "us" -#else - | k >= 1e-6 = (k*1e6) `with` "μs" -#endif - | k >= 1e-9 = (k*1e9) `with` "ns" - | k >= 1e-12 = (k*1e12) `with` "ps" - | k >= 1e-15 = (k*1e15) `with` "fs" - | k >= 1e-18 = (k*1e18) `with` "as" - | otherwise = printf "%g s" k - where with (t :: Double) (u :: String) - | t >= 1e9 = printf "%.4g %s" t u - | t >= 1e3 = printf "%.0f %s" t u - | t >= 1e2 = printf "%.1f %s" t u - | t >= 1e1 = printf "%.2f %s" t u - | otherwise = printf "%.3f %s" t u - dumpSVarStats :: SVar t m a -> SVarStats -> SVarStyle -> IO String dumpSVarStats sv ss style = do case yieldRateInfo sv of @@ -709,21 +683,17 @@ dumpSVarStats sv ss style = do then "\nheap max size = " <> show maxHp else "") <> (if minLat > 0 - then "\nmin worker latency = " - <> secs (fromIntegral minLat * 1e-9) + then "\nmin worker latency = " <> showNanoSecond64 minLat else "") <> (if maxLat > 0 - then "\nmax worker latency = " - <> secs (fromIntegral maxLat * 1e-9) + then "\nmax worker latency = " <> showNanoSecond64 maxLat else "") <> (if avgCnt > 0 then let lat = avgTime `div` fromIntegral avgCnt - in "\navg worker latency = " - <> secs (fromIntegral lat * 1e-9) + in "\navg worker latency = " <> showNanoSecond64 lat else "") <> (if svarLat > 0 - then "\nSVar latency = " - <> secs (fromIntegral svarLat * 1e-9) + then "\nSVar latency = " <> showRelTime64 svarLat else "") <> (if svarCnt > 0 then "\nSVar yield count = " <> show svarCnt diff --git a/src/Streamly/Time/Units.hs b/src/Streamly/Time/Units.hs index d67553766..ade70c1e8 100644 --- a/src/Streamly/Time/Units.hs +++ b/src/Streamly/Time/Units.hs @@ -1,5 +1,6 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE ScopedTypeVariables #-} #include "inline.hs" @@ -24,6 +25,7 @@ module Streamly.Time.Units , NanoSecond64(..) , MicroSecond64(..) , MilliSecond64(..) + , showNanoSecond64 -- * Absolute times (using TimeSpec) , AbsTime(..) @@ -43,10 +45,12 @@ module Streamly.Time.Units , fromRelTime64 , diffAbsTime64 , addToAbsTime64 + , showRelTime64 ) where import Data.Int +import Text.Printf (printf) ------------------------------------------------------------------------------- -- Some constants @@ -68,11 +72,25 @@ tenPower9 = 1000000000 -- Time Unit Representations ------------------------------------------------------------------------------- +-- XXX We should be able to use type families to use different represenations +-- for a unit. +-- +-- Second Rational +-- Second Double +-- Second Int64 +-- Second Integer +-- NanoSecond Int64 +-- ... + -- Double or Fixed would be a much better representation so that we do not lose -- information between conversions. However, for faster arithmetic operations -- we use an 'Int64' here. When we need convservation of values we can use a -- different system of units with a Fixed precision. --- + +------------------------------------------------------------------------------- +-- Integral Units +------------------------------------------------------------------------------- + -- | An 'Int64' time representation with a nanosecond resolution. It can -- represent time up to ~292 years. newtype NanoSecond64 = NanoSecond64 Int64 @@ -115,6 +133,10 @@ newtype MilliSecond64 = MilliSecond64 Int64 , Ord ) +------------------------------------------------------------------------------- +-- Fractional Units +------------------------------------------------------------------------------- + ------------------------------------------------------------------------------- -- TimeSpec representation ------------------------------------------------------------------------------- @@ -403,3 +425,47 @@ diffAbsTime (AbsTime t1) (AbsTime t2) = RelTime (t1 - t2) {-# INLINE addToAbsTime #-} addToAbsTime :: AbsTime -> RelTime -> AbsTime addToAbsTime (AbsTime t1) (RelTime t2) = AbsTime $ t1 + t2 + +------------------------------------------------------------------------------- +-- Formatting and printing +------------------------------------------------------------------------------- + +-- | Convert nanoseconds to a string showing time in an appropriate unit. +showNanoSecond64 :: NanoSecond64 -> String +showNanoSecond64 time@(NanoSecond64 ns) + | time < 0 = '-' : showNanoSecond64 (-time) + | ns < 1000 = fromIntegral ns `with` "ns" +#ifdef mingw32_HOST_OS + | ns < 1000000 = (fromIntegral ns / 1000) `with` "us" +#else + | ns < 1000000 = (fromIntegral ns / 1000) `with` "μs" +#endif + | ns < 1000000000 = (fromIntegral ns / 1000000) `with` "ms" + | ns < (60 * 1000000000) = (fromIntegral ns / 1000000000) `with` "s" + | ns < (60 * 60 * 1000000000) = + (fromIntegral ns / (60 * 1000000000)) `with` "min" + | ns < (24 * 60 * 60 * 1000000000) = + (fromIntegral ns / (60 * 60 * 1000000000)) `with` "hr" + | ns < (365 * 24 * 60 * 60 * 1000000000) = + (fromIntegral ns / (24 * 60 * 60 * 1000000000)) `with` "days" + | otherwise = + (fromIntegral ns / (365 * 24 * 60 * 60 * 1000000000)) `with` "years" + where with (t :: Double) (u :: String) + | t >= 1e9 = printf "%.4g %s" t u + | t >= 1e3 = printf "%.0f %s" t u + | t >= 1e2 = printf "%.1f %s" t u + | t >= 1e1 = printf "%.2f %s" t u + | otherwise = printf "%.3f %s" t u + +-- In general we should be able to show the time in a specified unit, if we +-- omit the unit we can show it in an automatically chosen one. +{- +data UnitName = + Nano + | Micro + | Milli + | Sec +-} + +showRelTime64 :: RelTime64 -> String +showRelTime64 = showNanoSecond64 . fromRelTime64