没有模块 Data.ByteString 的堆分析数据

6bb*_*df9 5 haskell memory-profiling bytestring

我试图为以下复制文件的原始 Haskell 代码生成堆内存配置文件:

import System.Environment
import System.IO
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as LB

naiveCopy :: String -> String -> IO ()
naiveCopy from to = do
  putStrLn $ "From: " ++ from
  putStrLn $ "To: " ++ to
  s <- B.readFile from
  B.writeFile to s

main = do
  args <- getArgs
  mapM (\ x-> putStrLn x) args
  naiveCopy (head args) ((head.tail) args)
Run Code Online (Sandbox Code Playgroud)

使用 ghc 8.0.1 构建代码的命令:

ghc -o t -rtsopts -prof -fprof-auto t.hs
Run Code Online (Sandbox Code Playgroud)

收集分析数据的命令:

./t +RTS -p -h -RTS in/data out/data && hp2ps -e8in -c t.hp
Run Code Online (Sandbox Code Playgroud)

哪里in/data是一个相当大的文件(大约 500MB),它需要大约 2 秒的时间来复制程序。

问题是如果我使用 strict ,我无法获得堆分析数据Data.ByteString,只有一个没有任何示例数据的小 t.hp 文件,它看起来像这样:

JOB "t in/data out/data +RTS -p -h"
DATE "Thu Aug  4 20:19 2016"
SAMPLE_UNIT "seconds"
VALUE_UNIT "bytes"
BEGIN_SAMPLE 0.000000
END_SAMPLE 0.000000
BEGIN_SAMPLE 0.943188
END_SAMPLE 0.943188
Run Code Online (Sandbox Code Playgroud)

和相应的配置文件图表如下: 不分析数据的严格 ByteString

不过,我可以得到堆,如果我切换到懒惰的版本分析数据Data.ByteString.Lazy,剖析图所示: 带有分析数据的 Lazy ByteString

更新:感谢@ryachza,我添加了一个-i0参数来设置采样间隔并再次尝试,这次我得到了严格的样本数据,ByteString看起来很合理(我正在复制一个 500M 的文件,下面的分析图表中的内存分配峰值约为 500M)

./t +RTS -p -h -RTS in/data out/data && hp2ps -e8in -c t.hp
Run Code Online (Sandbox Code Playgroud)

带有分析数据的严格 ByteString

rya*_*hza 4

运行时似乎没有“有机会测量”堆。如果您添加-s选项RTS,它应该打印一些时间和分配信息。当我运行这个程序时,我看到分配的字节数和总内存使用量非常高(文件大小),但最大驻留时间(和样本数)非常低,虽然经过的时间很高,但实际“工作” “时间几乎为0。

添加 RTS 选项-i0使我能够将字节串分配可重复地可视化为PINNED(这是分类,因为字节串内部使用的字节数组分配在 GC 无法移动内容的区域中)。您可以尝试不同的-h选项,将分配关联到不同的成本中心(例如,-hy应该显示ARR_WORDS),但在这种情况下它可能没有太大价值,因为字节串实际上只是“大块原始内存”。

我用来查找 RTS 选项的参考资料是(显然我并不特别关注 GHC 版本 - 我无法想象这些标志会频繁更改):

  1. https://downloads.haskell.org/~ghc/7.0.1/docs/html/users_guide/runtime-control.html
  2. https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/profiling.html