gpt4 book ai didi

haskell - 从 GHC 分析器中理解

转载 作者:行者123 更新时间:2023-12-02 15:58:28 25 4
gpt4 key购买 nike

我试图从 GHC 分析器中理解。有一个相当简单的应用程序,它使用 werqlens-aeson 库,在学习 GHC 分析时,我决定尝试一下。

使用不同的选项(time 工具、+RTS -p -RTS+RTS -p -h)我获得了完全不同的数字我的内存使用情况。有了所有这些数字,我现在完全无法理解正在发生的事情以及应用程序实际使用了多少内存。

这种情况让我想起了 Arthur Bloch 的一句话:“一个带着 watch 的人知道现在是什么时间。一个拥有两 block watch 的人永远不确定。”

请您建议我如何读取所有这些数字,以及每个数字的含义是什么。

以下是数字:

time -l 报告大约19M

#/usr/bin/time -l ./simple-wreq
...
3.02 real 0.39 user 0.17 sys
19070976 maximum resident set size
0 average shared memory size
0 average unshared data size
0 average unshared stack size
21040 page reclaims
0 page faults
0 swaps
0 block input operations
0 block output operations
71 messages sent
71 messages received
2991 signals received
43 voluntary context switches
6490 involuntary context switches

使用+RTS -p -RTS标记大约92M的报告。虽然它说“总分配”,但对我来说似乎很奇怪,像这样一个简单的应用程序可以分配和释放 91M

# ./simple-wreq +RTS -p -RTS      
# cat simple-wreq.prof
Fri Oct 14 15:08 2016 Time and Allocation Profiling Report (Final)

simple-wreq +RTS -N -p -RTS

total time = 0.07 secs (69 ticks @ 1000 us, 1 processor)
total alloc = 91,905,888 bytes (excludes profiling overheads)

COST CENTRE MODULE %time %alloc

main.g Main 60.9 88.8
MAIN MAIN 24.6 2.5
decodeLenient/look Data.ByteString.Base64.Internal 5.8 2.6
decodeLenientWithTable/fill Data.ByteString.Base64.Internal 2.9 0.1
decodeLenientWithTable.\.\.fill Data.ByteString.Base64.Internal 1.4 0.0
decodeLenientWithTable.\.\.fill.\ Data.ByteString.Base64.Internal 1.4 0.1
decodeLenientWithTable.\.\.fill.\.\.\.\ Data.ByteString.Base64.Internal 1.4 3.3
decodeLenient Data.ByteString.Base64.Lazy 1.4 1.4


individual inherited
COST CENTRE MODULE no. entries %time %alloc %time %alloc

MAIN MAIN 443 0 24.6 2.5 100.0 100.0
main Main 887 0 0.0 0.0 75.4 97.4
main.g Main 889 0 60.9 88.8 75.4 97.4
object_ Data.Aeson.Parser.Internal 925 0 0.0 0.0 0.0 0.2
jstring_ Data.Aeson.Parser.Internal 927 50 0.0 0.2 0.0 0.2
unstream/resize Data.Text.Internal.Fusion 923 600 0.0 0.3 0.0 0.3
decodeLenient Data.ByteString.Base64.Lazy 891 0 1.4 1.4 14.5 8.1
decodeLenient Data.ByteString.Base64 897 500 0.0 0.0 13.0 6.7
....

+RTS -p -hhp2ps 显示以下图片和两个数字:标题中的 114K 以及 周围的内容图表上>1.8MbMemory Profiling

并且,为了以防万一,这是该应用程序:

module Main where

import Network.Wreq
import Control.Lens
import Data.Aeson.Lens
import Control.Monad

main :: IO ()
main = replicateM_ 10 g
where
g = do
r <- get "http://httpbin.org/get"
print $ r ^. responseBody
. key "headers"
. key "User-Agent"
. _String

更新 1:感谢大家的精彩回复。正如建议的那样,我添加了 +RTS -s 输出,以便为每个阅读它的人构建整个图片。

#./simple-wreq +RTS -s
...
128,875,432 bytes allocated in the heap
32,414,616 bytes copied during GC
2,394,888 bytes maximum residency (16 sample(s))
355,192 bytes maximum slop
7 MB total memory in use (0 MB lost due to fragmentation)

Tot time (elapsed) Avg pause Max pause
Gen 0 194 colls, 0 par 0.018s 0.022s 0.0001s 0.0022s
Gen 1 16 colls, 0 par 0.027s 0.031s 0.0019s 0.0042s

更新 2:可执行文件的大小:

#du -h simple-wreq
63M simple-wreq

最佳答案

A man with a watch knows what time it is. A man with two watches is never sure.

啊,但是两只 watch 能显示什么呢?两者都旨在显示 UTC 的当前时间吗?或者其中一个应该显示 UTC 时间,另一个应该显示火星上某一点的时间?只要他们同步,第二种情况就不会有问题,对吗?

这正是这里发生的事情。您比较不同的内存测量值:

  • 最长居住期限
  • 分配的内存总量

最大驻留量是程序在给定时间使用的最大内存量。那是 19MB。然而,分配的内存总量要多得多,因为这就是 GHC 的工作原理:它为垃圾收集的对象“分配”内存,这几乎是所有未解压的对象。

让我们检查一个 C 示例:

int main() {
int i;
char * mem;

for(i = 0; i < 5; ++i) {
mem = malloc(19 * 1000 * 1000);
free(mem);
}
return 0;
}

每当我们使用malloc时,我们将分配 19 MB 内存。然而,我们随后立即释放了内存。因此,我们曾经拥有的最高内存量是 19 MB(堆栈和程序本身还多一点)。

但是,我们总共分配了 5 * 19M,总共 95M。不过,我们只需 20 兆 RAM 就可以运行我们的小程序。这就是总分配内存最大驻留时间之间的差异。请注意,按时间报告的居住地始终至少为 du <executable> ,因为它也必须驻留在内存中。

话虽这么说,生成统计数据的最简单方法是 -s ,这将显示从 Haskell 程序的角度来看最大驻留时间是多少。在您的情况下,它将是 1.9M,即您的堆配置文件中的数字(或由于分析而加倍的数量)。是的,Haskell 可执行文件往往会变得非常大,因为库是静态链接的。

关于haskell - 从 GHC 分析器中理解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40044364/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com