Home
Objective Caml
ocaml@conference.jabber.ru
Четверг, 26 мая 2011< ^ >
gds установил(а) тему: Камль -- http://caml.inria.fr | Логи -- http://chatlogs.jabber.ru/ocaml@conference.jabber.ru/ | Светлое будущее -- http://camlunity.ru/ | Нефильтрованное настоящее -- https://github.com/camlunity/kamlo_wiki | Портер прошлое -- http://gdsfh.dyndns.org/kamlo/ | Верблюды грязи не боятся! | release crap, enjoy NIH | репортьте баги официальным дилерам | ocaml мёртв, move on
Конфигурация комнаты
Участники комнаты

GMT+4
[00:21:34] gds вышел(а) из комнаты
[00:32:03] ygrek вышел(а) из комнаты
[00:51:50] arhibot вошёл(а) в комнату
[01:01:16] Kakadu вышел(а) из комнаты
[01:02:08] ermine вышел(а) из комнаты
[01:04:28] arhibot вышел(а) из комнаты
[01:38:02] Typhon вошёл(а) в комнату
[02:15:17] zbroyar вошёл(а) в комнату
[02:15:27] <zbroyar> Привет
[02:15:36] <zbroyar> Есть хто живой?
[02:31:22] <komar> Шо?
[02:46:02] <zbroyar> Та хотел спросить, может кто умеет готовить Gc
[02:49:05] <komar> Все умеют по чуть-чуть.
[02:49:47] <komar> Это ж жаббер-конфа, спроси и приходи потом.
[02:52:09] <zbroyar> Вобщем, задача банальна: нужно парсить логи
[02:52:24] <zbroyar> Логи большие, гиг по 5-10 каждый
[02:53:18] <zert> не надо такие логи парсить
[02:53:22] <zert> удали их, легче станет
[02:54:16] <zbroyar> Они денег стоят :-)
[02:54:38] <komar> Уж не трейсы ли?
[02:55:13] <zbroyar> Обнаружил, что если делать Gc.compact каждые 200К строк, то все работает гораздо быстрее, чем если не делать или делать просто full_major
[02:56:13] <zbroyar> Не трейсы
[02:57:17] <zbroyar> История взаимоотношений людей с одним фин. сервисом. Data mining
[02:58:13] <zbroyar> Короче, хочется понять, как настроить параметры памяти так, чтоб делать компакт хотя-б раз на миллион записей
[02:59:09] <zbroyar> А то сейчас картинка выглядит как-то так:
[02:59:13] <zbroyar> parsed 180000 in 0.145240 secs
parsed 190000 in 0.264231 secs
parsed 200000 in 0.118716 secs
parsed 210000 in 3.758706 secs
parsed 220000 in 0.093854 secs
[02:59:41] <zbroyar> То-есть после 200К запускается compact и три секунды работает.
[03:00:12] <zbroyar> И беда в том, что после след. 200К записей время сборки мусора увеличивается
[03:00:51] <zbroyar> Например, после разбора 1.6М записей compact уже работает 12 сек:
[03:00:56] <zbroyar> parsed 1590000 in 0.177808 secs
parsed 1600000 in 0.178705 secs
parsed 1610000 in 12.041362 secs
parsed 1620000 in 0.135850 secs
[03:06:21] Typhon вышел(а) из комнаты
[03:06:44] Typhon вошёл(а) в комнату
[03:37:19] <Typhon> zbroyar, http://elehack.net/michael/blog/2010/06/ocaml-memory-tuning
[03:37:42] zert вышел(а) из комнаты
[03:43:33] Digimmortal вошёл(а) в комнату
[03:43:35] Digimmortal вышел(а) из комнаты
[03:43:51] Digimmortal вошёл(а) в комнату
[03:46:31] <zbroyar> Дякую, це я вже знайшов :-)
[03:46:39] <zbroyar> Спасибо, то-есть
[03:48:38] <Typhon> а после запятой как перевести? :-)
[03:48:48] <zbroyar> Это я уже нашел
[04:07:25] Typhon вышел(а) из комнаты
[04:52:11] Digimmortal вышел(а) из комнаты
[05:07:58] zbroyar вышел(а) из комнаты
[09:04:00] gds вошёл(а) в комнату
[10:23:40] <f[x]> https://github.com/camlunity/kamlo_wiki/blob/HEAD/Gc.md
[10:25:20] <f[x]> интересно, по идее время компактинга должно быть пропорционально размеру heap'а и числу чанков
[10:25:31] <f[x]> может major_increment стоит увеличить
[10:40:05] ermine вошёл(а) в комнату
[10:48:01] ftrvxmtrx вышел(а) из комнаты
[11:48:33] Kakadu вошёл(а) в комнату
[11:49:44] ftrvxmtrx вошёл(а) в комнату
[12:13:15] Typhon вошёл(а) в комнату
[12:38:18] zert вошёл(а) в комнату
[12:42:53] ygrek вошёл(а) в комнату
[13:42:21] ygrek вышел(а) из комнаты
[14:46:32] Digimmortal вошёл(а) в комнату
[14:46:39] Digimmortal вышел(а) из комнаты
[14:46:54] Digimmortal вошёл(а) в комнату
[15:15:40] zbroyar вошёл(а) в комнату
[15:16:17] <zbroyar> Вобщем, решил
[15:17:41] <zbroyar> Проблема была в GC: я сначала читал все в список, а потом натравливал на него List.rev_map
[15:18:20] <zbroyar> Немного в сторону, вообще я хотел сравнить производительность регулярок Str и Pcre
[15:18:40] <zbroyar> а в результате разобрался з Gc
[15:19:06] <zbroyar> Вобщем, при подходе с List.rev_map очень сильно помог следующий кусочек:
[15:19:42] <zbroyar> let _ =
Gc.set
  { (Gc.get()) with
   Gc.minor_heap_size = 8000000;
   Gc.major_heap_increment = 64000000;
   Gc.space_overhead = 200;
   Gc.verbose = 4 (* to see what happens in the heap *)
  }
[15:20:12] <zbroyar> Gc.verbose можно опустить
[15:22:17] <zbroyar> Хотя в конце концов выгоднее всего оказалось поменять подход:
[15:23:40] <zbroyar> я поменял чтение всех строк в список и последующий парсинг на парсинг каждой входящей строки і добавление в список готового результата
[15:23:52] <zbroyar> let map f ch =
let rec loop l =
  let s = try Some (input_line ch) with End_of_file -> None in
  match s with
   Some s -> loop ((f s) :: l)
  | None -> l in
loop []
[15:24:35] <zbroyar> При таком подходе управление памятью тоже дает прирост производительности, но _очень_ небольшой
[15:24:38] <gds> zbroyar: а что дальше будешь делать с этим списком?  потому что можно вообще Stream использовать.
[15:26:46] <zbroyar> Дальше я буду сворачивать его в множество почасовых статистик
[15:27:04] <zbroyar> и множество профилей пользователей
[15:27:21] <gds> то есть, по сути, идти по нему последовательно, к обработанным записям не возвращаясь?
[15:27:46] <zbroyar> Так точно
[15:27:59] <gds> используй Stream.  Ща приведу примеры.
[15:30:20] <gds> zbroyar: вот мои местные расширения Stream: http://paste.in.ua/2455/
[15:30:33] <zbroyar> Дякую, зараз гляну
[15:30:40] <gds> там мусора достаточно, не всё нужно.
[15:30:43] <gds> ща ещё найду кое-что.
[15:33:41] <zbroyar> Stream'у не вистачає fold'інга
[15:35:25] <gds> факт.  но он пишется легко.
[15:36:54] <zbroyar> Через peek/junk?
[15:37:43] <gds> zbroyar: вот мой модуль Filew: http://paste.in.ua/2456/ -- там stream_of_*_lines
[15:38:09] <gds> fold -- лично я бы именно peek/junk делал.
[15:39:16] <gds> либо можно один раз написать себе fold_of_iter : (('a -> unit) -> 'r -> unit) -> (('a -> 'b -> 'b) -> 'a -> 'r -> 'a)
[15:39:24] <zbroyar> Останнє посилання, рядок 21
[15:39:31] <zbroyar> Це все, що мені потрібно, насправді
[15:39:49] <gds> тогда всё круто.
[15:39:51] <zbroyar> Stream, imho, тут просто зайва стуність
[15:40:38] <zbroyar> Якось дивно, що я до fold_channel_lines сам раніше не додумався ;-)
[15:40:42] <gds> Stream зато универсальное.
[15:41:25] <zbroyar> Я колись писав на плюсах, а там зайві пара сотень рядків коду - не крюк :-)
[15:43:56] <gds> понятно, но я бы всё-таки брал Stream (где-то полгода назад).  У него есть Stream.map (показал на копипастилке), можно сделать Stream.fold, можно брать не только из файла, можно хитро преобразовывать потоки.
Сейчас я бы взял для этой задачи итераты.
[15:44:18] <zbroyar> Ітерати?
[15:45:17] <gds> http://okmij.org/ftp/Streams.html
[15:46:22] <zbroyar> imho, fold - проста базова операція, до якої зводиться все, крім map
[15:46:40] <gds> а если взять fold + reverse, то и map.
[15:46:41] <zbroyar> Те, що ти мені кинув - це для якихось складних випадків.
[15:47:03] <gds> ну да.
[15:48:17] <zbroyar> У мене все просто: взяти 300G даних, і згорнути їх в профілі користувачів та множину статистик
[15:48:30] <zbroyar> Тобто, вхідний потік фактично один
[15:49:43] <gds> понял.  Тогда проще fold по строкам файла и не париться.
[15:49:59] <zbroyar> ... а ще я не дружу з синтаксисом хаскеля :-)
[15:51:13] <gds> а я -- с семантикой.  Поэтому http://ocaml-iteratees.forge.ocamlcore.org/
[15:51:24] <zbroyar> :-D
[15:52:28] <zbroyar> Дякую
[15:53:01] <zbroyar> Забрав, розберусь на дозвіллі
[15:55:44] <zbroyar> Що за формат .md?
[15:55:48] <gds> но смотри, вообще итераты хороши, но не везде нужны.
[15:56:02] <gds> .md -- "молдавские" наверное :]
[15:56:29] <zbroyar> Я про https://github.com/camlunity/kamlo_wiki/blob/HEAD/Gc.md
[15:56:46] <zbroyar> outline'інг якийсь?
[15:57:06] <gds> markdown видимо.
[15:57:22] <gds> github-flavored, да.
[16:04:57] <zbroyar> дякую
[16:11:33] <f[x]> http://pastebin.com/pw2AnBeE
[16:11:48] <f[x]> gds спалился как cvs-юзер
[16:12:14] <zbroyar> :-D
[16:12:50] <zert> позор
[16:14:33] <gds> омг, как мне с этим жить?!
[16:32:55] Kakadu вышел(а) из комнаты: Replaced by new connection
[16:32:55] Kakadu вошёл(а) в комнату
[17:00:13] gds вышел(а) из комнаты
[17:00:30] zbroyar вышел(а) из комнаты
[17:00:56] gds вошёл(а) в комнату
[17:04:26] ftrvxmtrx вышел(а) из комнаты
[17:25:53] Kakadu вышел(а) из комнаты
[17:26:04] Kakadu вошёл(а) в комнату
[17:32:58] gds вышел(а) из комнаты
[17:56:34] <Digimmortal> а BatEnum не аналог стрима?
[17:56:43] <Digimmortal> я так понимаю оно ленивое
[17:56:47] <Digimmortal> или гоню?
[17:59:01] <Typhon> ленивое и насколько я помню рекомендуется к использованию вместо стримов
[17:59:37] <Digimmortal> у мня вот таже такое впечатление сложилось после чтения доки
[18:00:27] <Digimmortal> я вот вообще не понимаю зачем списки нужны, когда есть ленивые последовательности
[18:46:42] Kakadu вышел(а) из комнаты
[18:48:13] komar вышел(а) из комнаты: Replaced by new connection
[18:48:14] komar вошёл(а) в комнату
[18:54:12] gds вошёл(а) в комнату
[19:00:04] <gds> Digimmortal: 1. списки быстрее и легковеснее в памяти.  2. если есть список, значит он уже вычислен и для его использования все ресурсы уже потрачены (цпу, память) и закрыты (дескрипторы) -- это гарантирует и скорость (деконструкция -- пара инструкций процессора), и безопасность (ничего не утечёт), и ничего не закроют внезапно в другой части программы.  3. ввод-вывод через ленивые списки/последовательности -- отстой в целом, так как и не гарантирует ничего (например, времени вызова функции recv()), и ошибконезащищённый (см. историю появления iteratees).
[19:00:58] <Digimmortal> а если нужно кучу трансформаций применять к последовательности?
[19:01:17] <Digimmortal> а она в файле лежит
[19:01:53] <Digimmortal> по поводу ошибконезащищённости - а в строгом языке какие грабли с этим?
[19:04:22] <gds> кучу трансформаций к последовательности -- можно, как и к списку.  недопонял, в чём тут проблема.
в строгом языке всё, что fun x ->, за if, за match, вычисляется не строго, а в зависимости от каких-либо обстоятельств.  Вот, ленивые списки тоже вычисляются лениво, даже в строгом языке.  Натыкался в живом коде на такое: создаю поток на основе канала (stream_of_channel_lines) внутри with-штуки и радостно возвращаю его за пределы with, тем самым закрывая канал, который находится внутри Stream.t.
[19:07:48] <Digimmortal> with это отдельная тема
[19:07:57] <Digimmortal> надо её иметь просто в виду
[19:07:59] <gds> то есть, с ленью (и с Stream.t как похожей штукой) надо аккуратно, она порой чертовски полезна, но добавляет геморы -- отладка, профайлинг.  Иногда проще вывернуть алгоритм, всего лишь переместив то, что было ленью, вовнутрь fun x -> и подобных конструкций, а деконструкцию ленивых значений превратить в конкретные вызовы функций и матчинг поверх значений.  Если представлять эту логику, можно полу-механически оформлять всё.
[19:08:38] <Digimmortal> если мы читаем что-то из файла и нам нужно не всё
[19:08:43] <Digimmortal> то лень к месту
[19:09:46] <Digimmortal> или агрегацию выполняем
[19:11:29] <Digimmortal> лень с сайд эффектами вообще стрёмная штука
[19:11:36] <Digimmortal> надо очень аккуратно
[19:13:38] <Digimmortal> в терминах безконечных последовательностей думать удобно
[19:13:46] <Digimmortal> и оно compositional
[19:14:15] <Digimmortal> можно писать в стиле юниховых конвейеров
[19:14:36] <Digimmortal> я этим регулярно в шарпе пользуюсь
[19:14:52] <Digimmortal> но иногда надо вовремя вычисление зафорсить
[19:15:12] <gds> о да, композиционируется замечательно.  Только разные стрёмные штуки бывают, типа как в мануле про LogicM Олег показывал: там был код вида [ x <- [1..] ; y <- [1..] ; z <- [1..] | x*x + y*y = z*z ], который слегка фейлит.
[19:15:41] <gds> конвееры -- да, тоже клёво.  На строгих списках, конечно, такого не сотворить.
[19:15:54] <Digimmortal> окамловый |> вообще песня с точки зрения читабельности и модифицируемости
[19:16:46] <Digimmortal> у всех компонент контекст супер компактный
[19:16:53] <Digimmortal> легко всё перетасовывать
[19:17:16] <Digimmortal> особенно, если тип по ходу не меняется
[19:20:31] <gds> а у меня |> мало прижился, только для быстрого-грязного кода использую.  Обычно не конвеер получается почему-то: либо надо на ошибки проверять специально, либо сначала напечатать, потом преобразовать дальше, либо типы на аргумент кое-где поставить, либо потом забываю, что именно имел ввиду (а в случае с let..in -- аргумент именованный таки).
[19:37:05] Digimmortal вышел(а) из комнаты
[20:28:54] Kakadu вошёл(а) в комнату
[21:37:08] Typhon вышел(а) из комнаты
[22:31:30] ftrvxmtrx вошёл(а) в комнату
[23:13:25] ermine вышел(а) из комнаты
[23:16:19] Kakadu вышел(а) из комнаты
[23:17:17] Kakadu вошёл(а) в комнату
[23:21:50] Kakadu вышел(а) из комнаты
[23:22:04] Kakadu вошёл(а) в комнату
[23:40:55] Typhon вошёл(а) в комнату
Powered by ejabberd Powered by Erlang Valid XHTML 1.0 Transitional Valid CSS!