http://www.haskell2025.org/ - Standard ML Family GitHub Project :-)
четверг, 2 июня 2016 г.
среда, 27 января 2016 г.
среда, 11 июня 2014 г.
Mio benchmark (GHC 7.8)
Наконец-то добрался протестировать производительность Mio ("Scalable IO Manager"), который появился в GHC 7.8. Предыдущей менеджер при переключении в threaded режим существенно терял производительность.
Тестирование производилось, используя реальное приложения, написанное на Haskell: RedisShardnig (http://github.com/kni/redis-sharding-hs-strict). Оно собиралась при помощи команды:
ghc -threaded -feager-blackholing -rtsopts -O2 --make redis_sharding.hs
Результаты сравнения Mio и старого менеджера.
FreeBSD (мой ноутбук: Intel(R) Pentium(R) CPU P6200)
Linux (какой-то сервер c 8 ядерами)
А вот данные как изменяется производительность с ростом количество рабочих OS threaded (параметр запуска -N):
GHC 7.8.1 threaded, Linux, 8 ядер.
Как видим, с выходом нового менеджера ввода-вывода производительность не только перестала падать при переключении в threaded режим, а даже стала возрастать!
Тестирование производилось, используя реальное приложения, написанное на Haskell: RedisShardnig (http://github.com/kni/redis-sharding-hs-strict). Оно собиралась при помощи команды:
ghc -threaded -feager-blackholing -rtsopts -O2 --make redis_sharding.hs
Результаты сравнения Mio и старого менеджера.
FreeBSD (мой ноутбук: Intel(R) Pentium(R) CPU P6200)
Requests per second
| | threaded
----------------------------
GHC 7.8.1 | 11560 | 12853
GHC 7.6.1 | 11210 | 7686
Linux (какой-то сервер c 8 ядерами)
Requests per second
| | threaded
----------------------------
GHC 7.8.1 | 16393 | 17605
GHC 7.6.1 | 16583 | 9354
А вот данные как изменяется производительность с ростом количество рабочих OS threaded (параметр запуска -N):
GHC 7.8.1 threaded, Linux, 8 ядер.
... +RTS -N1 ( 4 OS threads) - 15873.02 requests per second ... +RTS -N2 ( 6 OS threads) - 28735.63 requests per second ... +RTS -N3 ( 8 OS threads) - 29411.77 requests per second ... +RTS -N4 (10 OS threads) - 26954.18 requests per second
Как видим, с выходом нового менеджера ввода-вывода производительность не только перестала падать при переключении в threaded режим, а даже стала возрастать!
воскресенье, 1 сентября 2013 г.
Ждем Mio в GHC 7.8
Когда в GHC 7.0 появился "Scalable IO Manager", то стало возможным писать на Haskell TCP/IP сервера и использовать их в реальных условиях.
По скорости работы с текстовыми данными (ByteString) и списками GHC почти не уступает OCaml, Mlton, manticore(http://manticore.cs.uchicago.edu/), PolyML проигрывает 20%. Но GHC имеет лучший GC, чем у OCaml и Mlton, а manticore находиться пока в разработке.
Все бы было хорошо, но вот реализация самого "Scalable IO Manager" не оптимальная и приводит почти к двукратному снижению производительности. В связи с этим стал смотреть в сторону multiMLton и manticore, а также PolyML. Оценил насколько быстро можно к их менеджерам легковесных потоков добавить IO менеджеры, и понял, что трата времени на это будет для меня не рациональна.
Одновременно с этим узнал, что производительность существующего в GHC IO Manager не устраивает не только меня и нашлись люди, которые сделали
Mio: A High-Performance Multicore IO Manager for GHC.
Что-ж, ждем выхода GHC 7.8, который будет включать в себя Mio...
По скорости работы с текстовыми данными (ByteString) и списками GHC почти не уступает OCaml, Mlton, manticore(http://manticore.cs.uchicago.edu/), PolyML проигрывает 20%. Но GHC имеет лучший GC, чем у OCaml и Mlton, а manticore находиться пока в разработке.
Все бы было хорошо, но вот реализация самого "Scalable IO Manager" не оптимальная и приводит почти к двукратному снижению производительности. В связи с этим стал смотреть в сторону multiMLton и manticore, а также PolyML. Оценил насколько быстро можно к их менеджерам легковесных потоков добавить IO менеджеры, и понял, что трата времени на это будет для меня не рациональна.
Одновременно с этим узнал, что производительность существующего в GHC IO Manager не устраивает не только меня и нашлись люди, которые сделали
Mio: A High-Performance Multicore IO Manager for GHC.
Что-ж, ждем выхода GHC 7.8, который будет включать в себя Mio...
вторник, 26 февраля 2013 г.
Haskell - энергичный лентяй
Какая то ленивость у Haskell не правильная, слишком энергичная. :-)
Да, ленивость - это дело не простое, тут уметь надо.
Возьмем для примера функцию foldl. Ну какой лентяй будет как сумасшедший создавать столько чанков, что стек переполняется. На это способна только бешеная лисица, которой сотня километров - не крюк, на и Haskell.
Вы можете возразить, что вот ленивые списки - это окно в бесконечность. Да любая комбинация из функций map свалила бы Haskell в эту бесконечность, если бы не тщательно прописанные правила преобразования различных комбинаций функций. Да и вместо длинных списков предпочтительней использовать Stream Fusion.
Ну что это за ленивый язык, которому надо говорить, как правильно лениться?
Возьмем ленивые строки. Ну какие они ленивые!
Разве ленивая строка при добавлении данных в конец будет как бешеная лисица пробегать по всем чанкам? Нет, она сохранит данные в некотором буфере и добавит лишь когда эти данные понадобятся.
Ну а когда в результате некоторой операции данные в первом чанке заканчиваются, так называемая ленивая строка энергично переходит к следующей порции данных, например, прочитай их из сокета. Ну не торопись, поленись немного, дай определить, что будет чтение новой порции данный!
Что тут можно сказать? Лень - это не просто. Правильно лениться - уметь надо!
Да, ленивость - это дело не простое, тут уметь надо.
Возьмем для примера функцию foldl. Ну какой лентяй будет как сумасшедший создавать столько чанков, что стек переполняется. На это способна только бешеная лисица, которой сотня километров - не крюк, на и Haskell.
Вы можете возразить, что вот ленивые списки - это окно в бесконечность. Да любая комбинация из функций map свалила бы Haskell в эту бесконечность, если бы не тщательно прописанные правила преобразования различных комбинаций функций. Да и вместо длинных списков предпочтительней использовать Stream Fusion.
Ну что это за ленивый язык, которому надо говорить, как правильно лениться?
Возьмем ленивые строки. Ну какие они ленивые!
Разве ленивая строка при добавлении данных в конец будет как бешеная лисица пробегать по всем чанкам? Нет, она сохранит данные в некотором буфере и добавит лишь когда эти данные понадобятся.
Ну а когда в результате некоторой операции данные в первом чанке заканчиваются, так называемая ленивая строка энергично переходит к следующей порции данных, например, прочитай их из сокета. Ну не торопись, поленись немного, дай определить, что будет чтение новой порции данный!
Что тут можно сказать? Лень - это не просто. Правильно лениться - уметь надо!
среда, 6 февраля 2013 г.
RedisShardnig и GHC threaded
В последней версии RedisShardnig (http://github.com/kni/redis-sharding-hs-strict) буферизация данных и отправка их в сокеты происходит в отдельных user-lavel threads (forkIO), которым данные передаются посредством MVar переменных.
Разумеется, использование MVar имеет накладные расходы, но какие? Может, не смотря на некоторое усложнение кода, выгодней буфера таскать с собой?
Набросал простенький тестик, и кроме MVar добавил также RefIO. Тест показал, что и MVar и RefIO очень быстры и их можно использовать без опаски замедлить скорость выполнения программ.
Но тут я заметил, что компилировал без включения threaded ражима. А этот режим нужен, чтобы задействовать kqueue и epoll.
Скомпилировал я тесты в threaded режиме, запустил и увидел, что следует минимизировать их использование.
Но каждый тест является синтетическими, поэтому я решил вязать реальное приложение (RedisShardnig) и сделать версию с минимальным использованием MVar. В этой версии для буферизации не будут использоваться отдельные user-lavel threaded, с которыми общение происходит посредством MVar, а все буферизация будет происходить в рабочих threads и буыера будет таскаться с собой. Конечно множество MVar все равно останется, ведь при каждой операции записи чтения данных из сокетов используются MVar.
Текущая версия RedisShardnig (в таблице обозначена как mvar) и новая версия (в таблице обозначена как self) были собраны без и с поддержкой threaded режима и протестированы на производительность при помощи redis-benchmark (в 10 потоков). За RedisShardnig находилось 4 Redis node. Процессор имел 8 ядер. В таблице приведены тысячи SET запросов в секунду.
-P 100 - обозначает режим Pipeline с 100 команд в одном пакете (смотри redis-benchmark). То есть в этом режиме в 100 раз снижено количество отправки и получения данных из сокета.
Из таблицы видно, что для приложений с интенсивной сетевой нагрузкой включение threaded режима снижает производительность в 2 раза.
Впрочем и для приложений с другим характером нагрузки также заметно снижение производительность при использование threaded режима.
А не использовать threaded режим нельзя, так как для сетевых приложений необходим kqueue и epoll.
Кстати, разработчики GHC игнорируют это упущение.
Разумеется, использование MVar имеет накладные расходы, но какие? Может, не смотря на некоторое усложнение кода, выгодней буфера таскать с собой?
Набросал простенький тестик, и кроме MVar добавил также RefIO. Тест показал, что и MVar и RefIO очень быстры и их можно использовать без опаски замедлить скорость выполнения программ.
Но тут я заметил, что компилировал без включения threaded ражима. А этот режим нужен, чтобы задействовать kqueue и epoll.
Скомпилировал я тесты в threaded режиме, запустил и увидел, что следует минимизировать их использование.
Но каждый тест является синтетическими, поэтому я решил вязать реальное приложение (RedisShardnig) и сделать версию с минимальным использованием MVar. В этой версии для буферизации не будут использоваться отдельные user-lavel threaded, с которыми общение происходит посредством MVar, а все буферизация будет происходить в рабочих threads и буыера будет таскаться с собой. Конечно множество MVar все равно останется, ведь при каждой операции записи чтения данных из сокетов используются MVar.
Текущая версия RedisShardnig (в таблице обозначена как mvar) и новая версия (в таблице обозначена как self) были собраны без и с поддержкой threaded режима и протестированы на производительность при помощи redis-benchmark (в 10 потоков). За RedisShardnig находилось 4 Redis node. Процессор имел 8 ядер. В таблице приведены тысячи SET запросов в секунду.
-P 1 -P 100 mvar 19 83 mvar threaded 10 93 self 23 116 self threaded 13 107 mvar -N2 21 166 self -N2 26 208 mvar -N4 23 232 self -N4 25 263
-P 100 - обозначает режим Pipeline с 100 команд в одном пакете (смотри redis-benchmark). То есть в этом режиме в 100 раз снижено количество отправки и получения данных из сокета.
Из таблицы видно, что для приложений с интенсивной сетевой нагрузкой включение threaded режима снижает производительность в 2 раза.
Впрочем и для приложений с другим характером нагрузки также заметно снижение производительность при использование threaded режима.
А не использовать threaded режим нельзя, так как для сетевых приложений необходим kqueue и epoll.
Кстати, разработчики GHC игнорируют это упущение.
четверг, 31 января 2013 г.
Haskell Lazy vs Strict ByteString for Network
У привязки ленивой строки с сокету при помощи getContents есть один недостаток.
Невозможно определить есть ли еще данные во входном буфере.
А это иногда очень важно знать. Например, чтобы сделать оптимальную буферизацию.
Невозможно определить из-за того, что операции над ленивыми строками построены так, что когда данные заканчиваются, то сразу происходит чтение новой порции из сокета, а не при следующем обращение к строке. И это при том, что для текущей операции существующих данных было достаточно.
Невозможно определить есть ли еще данные во входном буфере.
А это иногда очень важно знать. Например, чтобы сделать оптимальную буферизацию.
Невозможно определить из-за того, что операции над ленивыми строками построены так, что когда данные заканчиваются, то сразу происходит чтение новой порции из сокета, а не при следующем обращение к строке. И это при том, что для текущей операции существующих данных было достаточно.
Подписаться на:
Сообщения (Atom)