benchmarking - Haskell: How to benchmark a computation accurately with deepseq/force -


i have web server written in haskell computes data in multiple steps.

i want accurately measure , display how long each action takes.

in presence of laziness, way this?


note "benchmarking" not quite right terminology since only want measure time in production system , not sample many runs. know case can use criterion.

you can use force control.deepseq evaluate data structure (and demand , measure computation).

one problem forcing large data structure takes time itself!

this because deepseq (used force) walk down algebraic data type tree, visiting every node (but not doing it).

when perform cheap operation each node, such map (*2) mylist, , try measure how long takes, overhead can become significant, messing measurements.

import control.deepseq import control.exception (evaluate) import data.time (diffutctime, getcurrenttime)   -- | measures how long computation takes, printing both time , -- overhead of `force` stdout. forces *twice*. benchmarkforce :: nfdata => string -> io -> io benchmarkforce msg action =     before <- getcurrenttime      -- force first time measure computation + forcing     result <- evaluate . force =<< action      after <- getcurrenttime      -- force again see how long forcing takes     _ <- evaluate . force $ result      afteragain <- getcurrenttime     putstrln $ msg ++ ": " ++ show (difftimems before after) ++ " ms"                    ++ " (force time: " ++ show (difftimems after afteragain) ++ " ms)"     return result              -- time difference `t2 - t1` in milliseconds         difftimems t1 t2 = realtofrac (t2 `diffutctime` t1) * 1000.0 :: double 

the first evaluate . force run make sure action , return value evaluated entirely.

by doing second force run on result, can measure how overhead added first traversal.

this of course comes @ expense of 2 traversals; being able measure how time deepseq wastes requires waste time twice.

here example measure pure functions that:

main :: io () main =      l <- benchmarkforce "create list" $         return [1..10000000 :: integer]      _ <- benchmarkforce "double each list element" $         return $ map (*2) l      _ <- benchmarkforce "map id l" $         return $ map id l      return () 

(of course works functions in io.)

the output:

create list: 1091.936 ms (force time: 71.33200000000001 ms) double each list element: 1416.0569999999998 ms (force time: 96.808 ms) map id l: 484.493 ms (force time: 67.232 ms) 

as can see, force creates around 13% overhead in map id l case.


Comments

Popular posts from this blog

html - How to style widget with post count different than without post count -

How to remove text and logo OR add Overflow on Android ActionBar using AppCompat on API 8? -

javascript - storing input from prompt in array and displaying the array -