测量碎片堆中的GC成本 - Haskell

时间:2017-08-28 14:29:39

标签: haskell garbage-collection ghc

我正在尝试对haskell中的碎片容差进行基准测试以进行实验。我用小数组填充堆,然后释放每个备用数组。然后我尝试分配一个大小的数组,大小相当于释放创建的孔的大小,并计算时间。这样做的结果是显示在约束堆设置中,GCing的成本比堆上有更多可用空间时更高且更难以预测。我的代码如下。我使用SmallObj的大型IO数组来跟踪小数组,确保它们不会被优化掉,并且还可以更容易地释放每个备用数组。

import Data.Array as AR
import Data.Array.IO as MA
import Control.Monad
import GHC.Stats
import System.Mem
import System.Environment
import System.IO
import Data.Time.Clock.POSIX

data SmallObj = SmallArray (IOArray Int Int) | Void
allocateArray num = do
    smallarr <- MA.newArray (1,2) num
    return smallarr

--fillHeap :: Int -> IO (IOArray Int (Maybe (IO(IOArray Int Int))))
fillHeap n = do
    temparr <- MA.newArray(1,2) 10
    let tempsarr = SmallArray (temparr)
    arr <- MA.newArray (1,n) tempsarr :: IO (IOArray Int SmallObj)
    traverseArray arr 1 n
    return arr


traverseArray arr n size
    | n <= size = do
                    smallarr <- allocateArray n
                    let ssmallarr = SmallArray (smallarr)
                    MA.writeArray arr n ssmallarr
                    traverseArray arr (n+1) size
    | otherwise = return arr

treadArray arr n size
    | n<=size = do
            b <- readArray arr n
            treadArray arr (n+1) size
    | otherwise = return ()

goThroughArray arr n size
    | n<=size = do
            b <- readArray arr n
            goThroughArray arr (n+1) size
    | otherwise = return ()

fragmentHeap lref n size
    | n <= size = do 
                          writeArray lref n Void
                          fragmentHeap lref (n+2) size
    | otherwise = return lref

putProgress :: Int -> IO ()
putProgress s = hPutStr stdout $ "\r\ESC[K" ++ show s

main = do
    args <- getArgs
    let size = read $ args!!0 :: Int -- 233570
    putStrLn "fillHeap"
    arr <- fillHeap size
    putStrLn "fragmentHeap"
    arr <- fragmentHeap arr 2 size
    putStrLn "\nmake small array"
    stats <- getGCStats
    putStrLn $ "Bytes allocated " ++ show(currentBytesUsed stats)
    tStart <- getPOSIXTime
    arr2 <- MA.newArray(1,1832957) 10 :: IO (IOUArray Int Int)
    tStop <- getPOSIXTime
    putStrLn $ "took " ++ show (tStop - tStart)
    treadArray arr2 1 1832957
    goThroughArray arr 1 size    
    stats <- getGCStats
    putStrLn $ "Bytes allocated " ++ show(currentBytesUsed stats)
    putStrLn ("done")

我面临的问题是,无论可用空间量多少,在碎片堆上分配大型数组所花费的时间几乎相同。我最初将堆大小固定为32兆,并且所有数组大小都是填充堆的最大可能大小。每次将堆大小增加10兆时,保持数组的大小分配相同,在分段(假设)堆上分配大数组所花费的时间不会像预期的那样减少。以下是一些示例输出:

./fragger2 233570 +RTS -T -M32477184 -RTS                                                                                   
fillHeap
fragmentHeap

make small array
Bytes allocated 31596064
took 0.004635s
Bytes allocated 31511432
done

当我将初始堆大小增加大约10 MB

./fragger2 233570 +RTS -T -M42477184 -RTS                                                                                     
fillHeap
fragmentHeap
make small array
Bytes allocated 17522368
took 0.004519s
Bytes allocated 31511432
done

相对较新的Haskell我想知道我是否正在测量时间,如果数组分配是一个monadic操作以任何方式影响时间,这就是为什么我得到相同的分配时间而不管可用空间在堆上?

0 个答案:

没有答案