Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.191.240.243] |
|
Сообщ.
#1
,
|
|
|
Добрый день!
Недавно начал пытаться использовать хаскелль в реальных задачах (конкретно - обработка звуковых сигналов), и застрял на производительности. Есть код, читающий сигнал из wav-файла: Wave.hs - содержит структуру данных Wave c "сырыми" данными, т.е. заголовком wav-файла и байтовой строкой с сигналом, + функционал по считыванию wav-файла в эту структуру. http://pastebin.com/wm53vVRx SignalSource.hs - содержит "чистовую" структуру данных, содерюащую сигнал и метаданные (пока только частоту), + функционал по преобразованию "сырых" данных в эту структуру. http://pastebin.com/Y7haSJX9 Signal.hs - собственно сигнал, по факту - список из Integer'ов с определенными арифметическими операциями. Для удобства в модуле Aux.List арифметические операции определены и для списков. http://pastebin.com/74V4qjGW Теперь, если попытаться прочитать wav-файл (размер ~225k) и посчитать длину сигнала (количество отсчетов): main = signalFromWave <$> readWaveFromFile sourceFile >>= print . sigLength . signal Оказвыается, что эта операция занимает аж 12 секунд. Собрал с ключиком -rtsopts и посмотрел вывод программы с ключами +RTS -sstderr. Вышло следующее: 9,071,278,288 bytes allocated in the heap 4,687,384,520 bytes copied during GC 2,555,736 bytes maximum residency (959 sample(s)) 169,472 bytes maximum slop 8 MB total memory in use (0 MB lost due to fragmentation) Tot time (elapsed) Avg pause Max pause Gen 0 10217 colls, 0 par 5.31s 5.32s 0.0005s 0.0017s Gen 1 959 colls, 0 par 3.63s 3.63s 0.0038s 0.0053s INIT time 0.00s ( 0.00s elapsed) MUT time 3.08s ( 3.08s elapsed) GC time 8.94s ( 8.94s elapsed) EXIT time 0.00s ( 0.00s elapsed) Total time 12.02s ( 12.03s elapsed) %GC time 74.3% (74.4% elapsed) Alloc rate 2,945,797,548 bytes per MUT second Productivity 25.7% of total user, 25.7% of total elapsed Т.е. программа вертится в пределах 8 мегабайт оперативы, но при этом так неистово аллоцирует память и чистит ее, что набегает аж 8.5 гигов за все время исполнения (просто чтение 225k данных и один проход по ним!). Как я понимаю, все дело в том, что при преобразовании ByteString в [Integer] у меня рекурсивно "откусывается" один Integer и заносится в список, после чего операция повторяетя с укороченной ByteString и увеличенным сигналом, т.е. в этот момент происходит перевыделение памяти под все данные, и память выделяется вместо одного раза по 225k аж {число отсчетов} x 225k. Тем не менее, я не могу понять, как это оптимизировать. В императивном языке я бы просто выделил массив байт заранее известного размера и считал бы все в него. Что можно сделать тут? P.S. Любые общие пожелания и комментарии по коду и стилю приветствуются. Wave читаю вручную специально (не прибегая к сторонним либам), чтобы поиграться с языком. |