I’m executing ssh commands with readProcess (from the System.Process package), and I’d like to time how long the execution takes and print that along with the command output.
I know it’s possible to time this accurately with criterion, but criterion seems to spend time doing a lot of setup and teardown as well as printing extra output. I’m not looking to run a full benchmark, just display how long the ssh command took to run.
So far I’ve tried the System.TimeIt package, but the results are incorrect. For example, this should report at least 5 seconds (just running sleep 5):
>>> timeIt $ readProcess "sleep" ["5"] []
CPU time: 0.04s
Here’s what System.TimeIt is doing under the hood:
-- |Wrap an 'IO' computation so that it prints out the execution time.
timeIt :: IO a -> IO a
timeIt ioa = do
(t, a) <- timeItT ioa
printf "CPU time: %6.2fs\n" t
return a
-- |Wrap an 'IO' computation so that it returns execution time is seconds as well as the real value.
timeItT :: IO a -> IO (Double, a)
timeItT ioa = do
t1 <- getCPUTime
a <- ioa
t2 <- getCPUTime
let t :: Double
t = fromIntegral (t2-t1) * 1e-12
return (t, a)
It seems straightforward enough, but I can’t figure out a way to force the execution of a <- ioa. Annotating with ! seems to make no difference.
Thanks!
Your problem here isn’t lazy evaluation–it’s that
sleepdoesn’t waste any CPU time on computing things, it just makes the program pause its execution during the given delay. SoTimeItis correctly reporting the amount of time your IO action spent on computation.Instead of
getCPUTime, you want to get wall clock time before and after the action that you want to time. TrygetCurrentTimeinData.Time.Clock.