Читаем Учебник по Haskell полностью

Время и общий объём памяти

Процесс отслеживания показателей память/скорость называется профилированием программы. Всё вро-

де бы работает, но работает слишком медленно, необходимо установить причину. Рассмотрим такую про-

грамму:

166 | Глава 10: Реализация Haskell в GHC

module Main where

concatR = foldr (++) []

concatL = foldl (++) []

fun :: Double

fun = test concatL - test concatR

where test f = last $ f $ map return [1 .. 1e6]

main = print fun

У нас есть подозрение, что какая-то из двух функций concatX работает слишком медленно. Мы можем

посмотреть какая, если добавим к ним специальную прагму SCC:

concatR = {-# SCC ”right” #-} foldr (++) []

concatL = {-# SCC ”left”

#-} foldl (++) []

Напомню, что прагмой называется специальный блочный комментарий с решёткой. Это специальное со-

общение компилятору. Прагмой SCC мы устанавливаем так называемый центр затрат (cost center). Она пи-

шется сразу за знаком равно. В кавычках пишется имя, под которым статиситика войдёт в итоговый отчёт.

После этого вычислитель будет следить за нагрузкой, которая приходится на эту функцию. Теперь нам нужно

скомпилировать модуль с флагом prof, который активирует подсчёт статистики в центрах затрат:

$ ghc --make concat.hs -rtsopts -prof -fforce-recomp

$ ./concat +RTS -p

Второй командой мы запускаем программу и передаём вычислителю флаг p. После этого будет создан

файл concat. prof. Откроем этот файл:

concat +RTS -p -RTS

total time

=

1.45 secs

(1454 ticks @ 1000 us, 1 processor)

total alloc = 1,403,506,324 bytes

(excludes profiling overheads)

COST CENTRE MODULE

%time %alloc

left

Main

99.8

99.8

individual

inherited

COST CENTRE MODULE

no.

entries

%time %alloc

%time %alloc

MAIN

MAIN

46

0

0.0

0.0

100.0

100.0

CAF

GHC.Integer.Logarithms.Internals

91

0

0.0

0.0

0.0

0.0

CAF

GHC.IO.Encoding.Iconv

71

0

0.0

0.0

0.0

0.0

CAF

GHC.IO.Encoding

70

0

0.0

0.0

0.0

0.0

CAF

GHC.IO.Handle.FD

57

0

0.0

0.0

0.0

0.0

CAF

GHC.Conc.Signal

56

0

0.0

0.0

0.0

0.0

CAF

Main

53

0

0.2

0.2

100.0

100.0

right

Main

93

1

0.0

0.0

0.0

0.0

left

Main

92

1

99.8

99.8

99.8

99.8

Мы видим, что почти всё время работы программа провела в функции concatL. Функция concatR была

вычислена мгновенно (time) и почти не потребовала ресусов памяти (alloc). У нас есть две пары колонок ре-

зультатов. individual указывает на время вычисления функции, а inherited – на время вычисления функции

и всех дочерних функций. Колонка entries указывает число вызовов функции. Если мы хотим проверить все

функции мы можем не указывать функции прагмами. Для этого при компиляции указывается флаг auto-all.

Отметим также, что все константы определённый на самом верхнем уровне модуля, сливаются в один центр.

Они называются в отчёте как CAF. Для того чтобы вычислитель следил за каждой константой по отдельности

необходимо указать флаг caf-all. Попробуем на таком модуле:

module Main where

fun1 = test concatL - test concatR

fun2 = test concatL + test concatR

Статистика выполнения программы | 167

test f = last $ f $ map return [1 .. 1e4]

concatR = foldr (++) []

concatL = foldl (++) []

main = print fun1 >> print fun2

Скомпилируем:

$ ghc --make concat2.hs -rtsopts -prof -auto-all -caf-all -fforce-recomp

$ ./concat2 +RTS -p

0.0

20000.0

После этого можно открыть файл concat2. prof и посмотреть итоговую статистику по всем значениям.

Программа с включённым профилированием будет работать гораздо медленей, не исключено, что ей не

хватит памяти на стеке, в этом случае вы можете добавить памяти с помощью флага вычислителя K, впрочем

если это произойдёт GHC подскажет вам что делать.

Динамика изменения объёма кучи

В предыдущем разделе мы смотрели общее время и память затраченные на вычисление функции. В этом

мы научимся измерять динамику изменения расхода памяти на куче. По этому показателю можно понять

в какой момент в программе возникают утечки памяти. Мы увидим характерные горбы на картинках, ко-

гда GC будет активно запрашивать новую память. Для этого сначала нужно скомпилировать программу с

флагом prof как и в предыдущем разделе, а при выполнении программы добавить один из флагов hc, hm,

hd, hy или hr. Все они начинаются с буквы h, от слова heap (куча). Вторая буква указывает тип графика,

какими показателями мы интересуемся. Все они создают специальный файл имяПриложения. hp, который мы

можем преобразовать в график в формате PostScript с помощью программы hp2ps, она устанавливается

автоматически вместе с GHC.

Рассмотрим типичную утечку памяти (из упражнения к предыдущей главе):

module Main where

import System.Environment(getArgs)

main = print . sum2 . xs . read =<< fmap head getArgs

where xs n = [1 .. 10 ^ n]

sum2 :: [Int] -> (Int, Int)

sum2 = iter (0, 0)

where iter c

[]

= c

iter c

(x:xs) = iter (tick x c) xs

tick :: Int -> (Int, Int) -> (Int, Int)

tick x (c0, c1) | even x

= (c0, c1 + 1)

| otherwise = (c0 + 1, c1)

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных