ня, далее для краткости мы будем называть его просто вычислителем. С флагом fforce -recomp программа
будет каждый раз заново пересобираться. Теперь посмотрим на статистику выполнения программы (флаг
s[file], в этом примере мы перенаправляем выход в поток stderr):
$ ./sum +RTS -sstderr
5.00005e9
14,145,284 bytes allocated in the heap
11,110,432 bytes copied during GC
2,865,704 bytes maximum residency (3 sample(s))
460,248 bytes maximum slop
7 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed)
Avg pause
Max pause
Gen
0
21 colls,
0 par
0.00s
0.01s
0.0006s
0.0036s
Gen
1
3 colls,
0 par
0.01s
0.01s
0.0026s
0.0051s
INIT
time
0.00s
(
0.00s elapsed)
MUT
time
0.01s
(
0.01s elapsed)
GC
time
0.01s
(
0.02s elapsed)
EXIT
time
0.00s
(
0.00s elapsed)
Total
time
0.02s
(
0.03s elapsed)
%GC
time
60.0%
(69.5% elapsed)
Alloc rate
1,767,939,507 bytes per MUT second
Productivity
40.0% of total user, 26.0% of total elapsed
Был распечатан результат и отчёт о работе программы. Разберёмся с показателями:
bytes allocated inthe heap
-- число байтов выделенных в куче
-- за всё время работы программы
bytes copied during GC
-- число скопированных байтов
-- за всё время работы программы
bytes maximum residency
-- в каком объёме памяти работала программа
-- в скобках указано число глубоких очисток
bytes maximum slop
-- максимум потерь памяти из-за фрагментации
total memory inuse
-- сколько всего памяти было запрошено у ОС
Показатель bytes maximum residency измеряется только при глубокой очистке, поскольку новая память
выделяется именно в этот момент. Размер памяти выделенной в куче гораздо больше общего объёма памяти.
Так происходит потому, что этот показатель указывает на общее число памяти в куче за всё время работы
программы. Ведь мы переиспользуем не нужную нам память. По этому показателю можно судить о том,
сколько замыканий (объектов) было выделено в куче.
Следующие две строчки говорят о числе сборок мусора. Мы видим, что GC выполнил 21 поверхностную
очистку (поколение 0) и 3 глубоких (покколение 1). Дальше идут показатели скорости. INITи EXIT– это
164 | Глава 10: Реализация Haskell в GHC
инициализация и завершение программы. MUT– это полезная нагрузка, время, которая наша программа тра-
тила на изменение (MUTation) значений. GC– время сборки мусора. Далее GHC сообщил нам о том, что мы
провели 60% времени в сборке мусора. Это очень плохо. Продуктивность программы очень низкая. Затратна
глубокая сборка мусора, поверхностная – это дело обычное. Теперь посмотрим на показатели строгой версии
этой программы:
module Main where
import Data.List(foldl’)
sum’ =foldl’ ( +) 0
main =print $sum’ [1 ..1e5]
Скомпилируем:
$ ghc --make sumStrict.hs -rtsopts -fforce-recomp
Посмотрим на статистику:
$ ./sumStrict +RTS -sstderr
5.00005e9
10,474,128 bytes allocated in the heap
24,324 bytes copied during GC
27,072 bytes maximum residency (1 sample(s))
27,388 bytes maximum slop
1 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed)
Avg pause
Max pause
Gen
0
19 colls,
0 par
0.00s
0.00s
0.0000s
0.0000s
Gen
1
1 colls,
0 par
0.00s
0.00s
0.0001s
0.0001s
INIT
time
0.00s
(
0.00s elapsed)
MUT
time
0.01s
(
0.01s elapsed)
GC
time
0.00s
(
0.00s elapsed)
EXIT
time
0.00s
(
0.00s elapsed)
Total
time
0.01s
(
0.01s elapsed)
%GC
time
0.0%
(3.0% elapsed)
Alloc rate
1,309,266,000 bytes per MUT second
Productivity 100.0% of total user, 116.0% of total elapsed
Мы видим, что произошла лишь одна глубокая сборка. И это существенно сказалось на продуктивности.
Кромке того мы видим, что программа заняла лишь 27 Кб памяти, вместо 2 Мб как в прошлом случае. Теперь
давайте покрутим ручки у GC. В GHC можно устанавливать разные параметры сборки мусора с помощью
флагов. Все флаги можно посмотреть в документации GHC. Мы обратим внимание на несколько флагов.
Флаг Hназначает минимальное значение для стартового объёма кучи. Флаг Aназначает объём памяти для
яслей. По умолчанию размер яслей равен 512 Кб (эта цифра может измениться). Изменением этих параметров
мы можем отдалить сборку мусора. Чем дольше работает программа между сборками, тем выше вероятность
того, что многие объекты уже не нужны.
Давайте убедимся в том, что поверхностные очистки происходят очень быстро и совсем не тормозят
программу. Установим размер яслей на 32 Кб вместо 512 Кб как по умолчанию (размер пишется сразу за
флагом, за цифрой идёт k или m):
$ ./sumStrict +RTS -A32k -sstderr
...
Tot time (elapsed)
Avg pause
Max pause
Gen
0
318 colls,
0 par
0.00s
0.00s
0.0000s
0.0000s
Gen
1
Читать дальше