<?xml version='1.0' encoding="utf-8"?>
      <rss version='2.0'>
      <channel>
      <title>Форум на Исходниках.RU</title>
      <link>https://forum.sources.ru</link>
      <description>Форум на Исходниках.RU</description>
      <generator>Форум на Исходниках.RU</generator>
  	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=406881&amp;view=findpost&amp;p=3635186</guid>
        <pubDate>Wed, 18 Nov 2015 10:30:06 +0000</pubDate>
        <title>[Haskell] Оптимизация и профилирование</title>
        <link>https://forum.sources.ru/index.php?showtopic=406881&amp;view=findpost&amp;p=3635186</link>
        <description><![CDATA[Da&#036;aD: Добрый день&#33;<br>
<br>
Недавно начал пытаться использовать хаскелль в реальных задачах (конкретно - обработка звуковых сигналов), и застрял на производительности.<br>
Есть код, читающий сигнал из wav-файла:<br>
<br>
Wave.hs - содержит структуру данных Wave c &quot;сырыми&quot; данными, т.е. заголовком wav-файла и байтовой строкой с сигналом, + функционал по считыванию wav-файла в эту структуру.<br>
<a class='tag-url' href='http://pastebin.com/wm53vVRx' target='_blank'>http://pastebin.com/wm53vVRx</a><br>
<br>
SignalSource.hs - содержит &quot;чистовую&quot; структуру данных, содерюащую сигнал и метаданные (пока только частоту), + функционал по преобразованию &quot;сырых&quot; данных в эту структуру.<br>
<a class='tag-url' href='http://pastebin.com/Y7haSJX9' target='_blank'>http://pastebin.com/Y7haSJX9</a><br>
<br>
Signal.hs - собственно сигнал, по факту - список из Integer&#39;ов с определенными арифметическими операциями. Для удобства в модуле Aux.List арифметические операции определены и для списков.<br>
<a class='tag-url' href='http://pastebin.com/74V4qjGW' target='_blank'>http://pastebin.com/74V4qjGW</a><br>
<br>
Теперь, если попытаться прочитать wav-файл (размер ~225k) и посчитать длину сигнала (количество отсчетов):<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">main = signalFromWave &#60;$&#62; readWaveFromFile sourceFile &#62;&#62;= print . sigLength . signal</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script><br>
<br>
Оказвыается, что эта операция занимает аж 12 секунд. Собрал с ключиком -rtsopts и посмотрел вывод программы с ключами +RTS -sstderr. Вышло следующее:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; 9,071,278,288 bytes allocated in the heap</div><div class="code_line">&nbsp;&nbsp; 4,687,384,520 bytes copied during GC</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; 2,555,736 bytes maximum residency (959 sample(s))</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; 169,472 bytes maximum slop</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 8 MB total memory in use (0 MB lost due to fragmentation)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Tot time (elapsed) &nbsp;Avg pause &nbsp;Max pause</div><div class="code_line">&nbsp;&nbsp;Gen &nbsp;0 &nbsp; &nbsp; 10217 colls, &nbsp; &nbsp; 0 par &nbsp; &nbsp;5.31s &nbsp; &nbsp;5.32s &nbsp; &nbsp; 0.0005s &nbsp; &nbsp;0.0017s</div><div class="code_line">&nbsp;&nbsp;Gen &nbsp;1 &nbsp; &nbsp; &nbsp; 959 colls, &nbsp; &nbsp; 0 par &nbsp; &nbsp;3.63s &nbsp; &nbsp;3.63s &nbsp; &nbsp; 0.0038s &nbsp; &nbsp;0.0053s</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;INIT &nbsp; &nbsp;time &nbsp; &nbsp;0.00s &nbsp;( &nbsp;0.00s elapsed)</div><div class="code_line">&nbsp;&nbsp;MUT &nbsp; &nbsp; time &nbsp; &nbsp;3.08s &nbsp;( &nbsp;3.08s elapsed)</div><div class="code_line">&nbsp;&nbsp;GC &nbsp; &nbsp; &nbsp;time &nbsp; &nbsp;8.94s &nbsp;( &nbsp;8.94s elapsed)</div><div class="code_line">&nbsp;&nbsp;EXIT &nbsp; &nbsp;time &nbsp; &nbsp;0.00s &nbsp;( &nbsp;0.00s elapsed)</div><div class="code_line">&nbsp;&nbsp;Total &nbsp; time &nbsp; 12.02s &nbsp;( 12.03s elapsed)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;%GC &nbsp; &nbsp; time &nbsp; &nbsp; &nbsp;74.3% &nbsp;(74.4% elapsed)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;Alloc rate &nbsp; &nbsp;2,945,797,548 bytes per MUT second</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;Productivity &nbsp;25.7% of total user, 25.7% of total elapsed</div></ol></div></div></div></div><br>
<br>
Т.е. программа вертится в пределах 8 мегабайт оперативы, но при этом так неистово аллоцирует память и чистит ее, что набегает аж 8.5 гигов за все время исполнения (просто чтение 225k данных и один проход по ним&#33;). Как я понимаю, все дело в том, что при преобразовании ByteString в [Integer] у меня рекурсивно &quot;откусывается&quot; один Integer и заносится в список, после чего операция повторяетя с укороченной ByteString и увеличенным сигналом, т.е. в этот момент происходит перевыделение памяти под все данные, и память выделяется вместо одного раза по 225k аж {число отсчетов} x 225k.<br>
<br>
Тем не менее, я не могу понять, как это оптимизировать. В императивном языке я бы просто выделил массив байт заранее известного размера и считал бы все в него. Что можно сделать тут?<br>
<br>
P.S. Любые общие пожелания и комментарии по коду и стилю приветствуются. Wave читаю вручную специально (не прибегая к сторонним либам), чтобы поиграться с языком.]]></description>
        <author>Da&#036;aD</author>
        <category>Прочие языки программирования</category>
      </item>
	
      </channel>
      </rss>
	