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] metaclass.livejournal.com 2011-10-31 02:27 pm (UTC)(link)
О, -ddump-simpl на вид гораздо понятнее.

[identity profile] artureg.livejournal.com 2011-10-31 02:28 pm (UTC)(link)
brainfuck

[identity profile] eminglorion.livejournal.com 2011-10-31 03:01 pm (UTC)(link)
На всякий случай оставлю здесь. У меня получилось так:
notNewLine =
  \ (ds :: Word8) ->
    case ds of _ { W8# a2 ->
    case eqWord# a2 __word 10 of _ {
      False ->
        case eqWord# a2 __word 13 of _ { False -> True; True -> False };
      True -> False
    }
    }

При инлайне распаковка case ds of _ { W8# a2 -> будет убрана. Собственно, это можно пронаблюдать в цикле, который разбивает файл на строки.