如何通过纯粹的功能计算“燃烧CPU”来最好地“浪费”大致指定的时间?

时间:2014-03-09 12:46:29

标签: haskell profiling

我偶尔会想要在开发/测试时延迟纯算法的特定部分,所以我可以通过观察逐个累积的懒惰结果来监视评估(这通常太快而无法在最终中使用) ,未延迟版本)。然后我发现自己插入了像sum [1..1000000] `seq` q这样的丑陋的东西,这种东西很常见(虽然通常会遇到通常的爆炸问题,因为我从来没有想过这个问题),但是它很像试错法。 / p>

当我想以这种方式进行一些快速测试并且无法进行适当的分析时,是否有一个更好,更可控的替代方案仍然同样简单,criterion等等。 >

我也想避免unsafePerformIO $ threadDelay,但我认为这可能是合适的用法。

1 个答案:

答案 0 :(得分:3)

这种循环解决方案可以避免调用threadDelay,但仍然会调用unsafePerformIO,所以我们可能收不到多少:

import Data.AdditiveGroup
import Data.Thyme.Clock
import Data.Thyme.Clock.POSIX
import System.IO.Unsafe

pureWait :: NominalDiffTime -> ()
pureWait time = let tsList = map unsafePerformIO ( repeat getPOSIXTime ) in
    case tsList of
        (t:ts) -> loop t ts
    where
        loop t (t':ts') = if (t' ^-^ t) > time
            then ()
            else loop t ts'

main :: IO ()
main = do
    putStrLn . show $ pureWait (fromSeconds 10)

更新:这是一个有效的解决方案。首先确定(使用IO)实现给定延迟需要多少次迭代,然后使用纯循环函数。

pureWait :: Integer -> Integer
pureWait i = foldl' (+) 0 $ genericTake i $ intersperse (negate 1) (repeat 1)

calibrate :: NominalDiffTime -> IO Integer
calibrate timeSpan = let iterations = iterate (*2) 2 in loop iterations
    where
    loop (i:is) = do
        t1 <- getPOSIXTime
        if pureWait i == 0
            then do
                t2 <- getPOSIXTime
                if (t2 ^-^ t1) > timeSpan
                   then return i
                   else loop is
            else error "should never happen"

main :: IO ()
main = do
    requiredIterations <- calibrate (fromSeconds 10)
    putStrLn $ "iterations required for delay: " ++ show requiredIterations
    putStrLn . show $ pureWait requiredIterations