我正在尝试对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操作以任何方式影响时间,这就是为什么我得到相同的分配时间而不管可用空间在堆上?