debug-time (empty) → 0.1.0.0
raw patch · 5 files changed
+134/−0 lines, 5 filesdep +basedep +clockdep +containerssetup-changed
Dependencies added: base, clock, containers, debug-time
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- debug-time.cabal +31/−0
- src/Debug/Time.hs +47/−0
- test/Test.hs +24/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Luka Horvat (c) 2015++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Luka Horvat nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ debug-time.cabal view
@@ -0,0 +1,31 @@+name: debug-time+version: 0.1.0.0+synopsis: Debug.Trace equivalent for timing computations+description: Please see README.md+homepage: http://github.com/LukaHorvat/debug-time#readme+license: MIT+license-file: LICENSE+author: Luka Horvat+maintainer: example@example.com+copyright: 2015 Luka Horvat+category: Debug+build-type: Simple+cabal-version: >=1.10++library+ hs-source-dirs: src+ default-language: Haskell2010+ exposed-modules: Debug.Time+ build-depends: base >= 4.7 && < 5+ , containers+ , clock+ ghc-options: -Wall++test-suite test+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Test.hs+ default-language: Haskell2010+ build-depends: base >= 4.7 && < 5+ , debug-time+ ghc-options: -Wall
+ src/Debug/Time.hs view
@@ -0,0 +1,47 @@+{-# OPTIONS_GHC -fno-cse -fno-full-laziness #-} +module Debug.Time (startTimer, traceTimer, restartTimer, initializeTimers) where + +import Data.Map (Map) +import qualified Data.Map as Map +import System.Clock (TimeSpec, timeSpecAsNanoSecs, getTime, diffTimeSpec, Clock(Monotonic)) +import System.IO.Unsafe (unsafePerformIO) +import Data.IORef (IORef) +import qualified Data.IORef as Ref +import Debug.Trace (trace) +import Control.Monad (void) +import Numeric + +{-# NOINLINE timers #-} +timers :: IORef (Map String TimeSpec) +timers = unsafePerformIO $! Ref.newIORef Map.empty + +{-# NOINLINE readTimer #-} +readTimer :: String -> Integer +readTimer name = unsafePerformIO $ do + now <- getTime Monotonic + time <- Map.lookup name <$> Ref.readIORef timers + case time of + Nothing -> error $ "Attempting to read the timer '" ++ name ++ "' that has not been started" + Just t -> return $! timeSpecAsNanoSecs (diffTimeSpec now t) + +-- | Initializes the timer store. This makes the first measurement more reliable." +initializeTimers :: IO () +initializeTimers = void $! Ref.readIORef timers + +-- | Ties the evaluation of the value with the start of a timer with the given name. +startTimer :: String -> a -> a +startTimer name x = start `seq` x where + start = unsafePerformIO $ do + time <- getTime Monotonic + Ref.modifyIORef' timers (Map.insert name time) + +-- | Ties the evaluation of the value with an action tracing the elapsed time +-- since the start of the timer. +traceTimer :: String -> a -> a +traceTimer name = trace (format (readTimer name)) + where format time = "Timer " ++ name ++ ": " ++ asSeconds time ++ " seconds." + asSeconds time = showFFloat Nothing (fromIntegral time / 1000000000 :: Double) "" + +-- | Synonym for startTimer. +restartTimer :: String -> a -> a +restartTimer = startTimer
+ test/Test.hs view
@@ -0,0 +1,24 @@+module Main where + +import Debug.Time + +-- | Naive implementation +fibs :: [Int] +fibs = map (fibAt . maybeTimer) [1..] + where maybeTimer 10 = startTimer "10-30" 10 + maybeTimer 30 = traceTimer "10-30" 30 + maybeTimer 20 = startTimer "20-40" 20 + maybeTimer 40 = traceTimer "20-40" 40 + maybeTimer n = n + +fibAt :: Int -> Int +fibAt 1 = 1 +fibAt 2 = 1 +fibAt n = fibAt (n - 1) + fibAt (n - 2) + +main :: IO () +main = do + initializeTimers + putStrLn "Calculating the first 40 fibonacci numbers while tracing the time elapsed between" + putStrLn "the computations 10-30 and 20-40" + mapM_ print (take 40 fibs)