metaclass: (Default)
metaclass ([personal profile] metaclass) wrote2011-10-31 04:45 pm
Entry tags:

Haskell, профилировщик

Проверяю, действительно ли enumerator+attoparsec работают в постоянной памяти.
Собираю с профилировочной информацией:
ghc.exe -odir obj -hidir obj --make "%1" -prof -auto-all -caf-all -fforce-recomp -rtsopts -fext-core
(если чо - в кабале перед установкой пакетов надо в конфиг поставить опцию library-profiling: True иначе будет ругаться при сборке)

затем запускаю прожку с профилировщиком
test.exe +RTS -p list2.txt >rr

list2.txt - файлик в 18 мег, 316 тыщ строк, список файлов на диске С :)

получаю файл test.prof, в котором есть такая забавная информация:
COST CENTRE                    MODULE               %time %alloc
main                           Main                  48.6    8.7
notNewLine                     Parsers               36.0   73.4
parseLine                      Parsers               10.6   15.5


notNewLine, который так интенсивно долбится в память - совершенно тупой предикат:
notNewLine :: Word8 -> Bool
notNewLine 10 = False -- LF
notNewLine 13 = False -- CR
notNewLine _  = True


Решил глянуть, что же ghc генерит для него:

  main:Parsers.notNewLine :: base:GHCziWord.Word8 ->
                             ghczmprim:GHCziBool.Bool =
    \ (dsd2xh::base:GHCziWord.Word8) ->
        %note "SCC"
        %case ghczmprim:GHCziBool.Bool (base:GHCziClasses.zeze
                                        @ base:GHCziWord.Word8 base:GHCziWord.zdfEqWord8 dsd2xh
                                        (base:GHCziNum.fromInteger @ base:GHCziWord.Word8
                                         base:GHCziWord.zdfNumWord8
                                         (integerzmgmp:GHCziInteger.smallInteger
                                          (10::ghczmprim:GHCziPrim.Intzh))))
        %of (wildB1::ghczmprim:GHCziBool.Bool)
          {ghczmprim:GHCziBool.False ->
             %case ghczmprim:GHCziBool.Bool (base:GHCziClasses.zeze
                                             @ base:GHCziWord.Word8 base:GHCziWord.zdfEqWord8 dsd2xh
                                             (base:GHCziNum.fromInteger @ base:GHCziWord.Word8
                                              base:GHCziWord.zdfNumWord8
                                              (integerzmgmp:GHCziInteger.smallInteger
                                               (13::ghczmprim:GHCziPrim.Intzh))))
             %of (wild1X9::ghczmprim:GHCziBool.Bool)
               {ghczmprim:GHCziBool.False ->
                  ghczmprim:GHCziBool.True;
                ghczmprim:GHCziBool.True ->
                  ghczmprim:GHCziBool.False};
           ghczmprim:GHCziBool.True ->
             ghczmprim:GHCziBool.False};



Если я правильно понимаю написанное - оно на каждый вызов предиката конвертирует числа в Word8, выделяя под это память, а то и не один раз?
Хотя это какая-то хрень, оно должно такое вычислить один раз и дальше использовать готовое, по идее.

PS: Ага, включил -O2 - предикат стал работать как положено - 2% времени и 0% памяти. И общее потребление памяти вообще упало в 5 раз.

[identity profile] eminglorion.livejournal.com 2011-10-31 02:21 pm (UTC)(link)
Рекомендую ghc -dsuppress-module-prefixes -dsuppress-uniques -dsuppress-coercions, иначе выдачу ghc читать невозможно. Это -ddump-simpl? А то на вид как-то неоптимизировано.

[identity profile] geeks-ru.livejournal.com 2011-10-31 03:46 pm (UTC)(link)
А оптимизация там проводится? (не вижу флага -O, он совместим с профилированием?)

[identity profile] ilya-portnov.livejournal.com 2011-10-31 04:06 pm (UTC)(link)
К PS: А, ну так ещё бы. Что-то, в чём важна эффективность по процессору и/или памяти, собирать без -O2 имхо вообще смысла не имеет :)

[identity profile] max630.livejournal.com 2011-10-31 04:36 pm (UTC)(link)
ну по -Sstderr обычно видно, постоянная там паметь или не постоянная

[identity profile] nivanych.livejournal.com 2011-11-01 02:06 am (UTC)(link)
> Ага, включил -O2

Ещё дам замечательный пример —
sum [1..10005000]
Запускать без -O2.