суббота, 10 июля 2010 г.

[soft] Попробовал упаковать 7-Zip-ом большой каталог

Пытаюсь перенести информацию со старого рабочего компьютера на новый с помощью внешнего винчестера (чтобы заодно и резервную копию всего получить). Попробовал сделать так: сначала запаковать то, что мне нужно, в архив с минимальным уровнем сжатия (архив пишется сразу на внешний диск), а потом распаковать его другой машине.

Решил воспользоваться 7-Zip-ом 4.65. Дошло дело до большущего рабочего каталога с несколькими десятками больших svn-новских рабочих копий. Общее количество файлов – порядка 2.8 миллионов, объем – около 36Gb.

И вот тут то обнаружилась засада. 7-Zip построил полный список файлов, отсортировал по именам и начал их архивировать в получившемся порядке. Т.е. не в порядке расположения каталогов и подкаталогов (скажем, сначала все из каталога aag_2, затем из aag_3, затем из ace, затем из docs, затем из emi_proto и т.д.), а по именам файлов. Сначала он стал сжимать все файлы с именами all-wcprops, затем entities, затем wc-properties, затем ChangeLog и т.д., вне зависимости от того, в каком каталоге эти файлы расположены.

Получилось, что за файлами all-wcprops архиватор сначала шел в каталог aag_2, затем в aag_3, затем в ace и т.д. Потом наступала очередь файла entities и архиватор опять шел в aag_2, aag_3, ace и далее по списку.

Как результат – очень низкая скорость работы. После одинадцати часов работы 7-Zip смог упаковать только 10Gb из 36 со средней скоростью упаковки 255Kb/s, предсказывая еще 29 часов для оставшихся файлов. Что не удивительно, поскольку вместо последовательного чтения содержимого каждого из подкаталогов (более-менее компактно размещающегося на диске), происходило постоянное перепрыгивание с одного места диска на другое. Пришлось 7-Zip прервать.

Сейчас запустил на аналогичном по структуре, но меньшем по объему, каталоге WinRar. Этот, вроде бы, читает файлы последовательно. И, как следствие, работает пошустрее.

Вот интересно, есть ли сейчас бесплатные архиваторы, позволяющие строить 7z или zip архивы, и которые читают содержимое каталогов строго последовательно? (Попробовал PeaZip, он очень прост – в режимах 7z и zip просто запускается консольная версия 7-Zip).

пятница, 9 июля 2010 г.

[prog] Теперь вот Rust от Mozilla – полку новых нативных языков прибывает

С осени прошлого года в поле зрения попадает уже третья попытка создать новый язык программирования, предназначенный для компиляции в нативный код. Первым был Zimbu от Брама Мулинара (разработчика ViM-а), затем Go от Google, а вот теперь Rust от Mozilla (спасибо ув.тов.Курилке за наводку).

Пока познакомиться с Rust-ом не удалось. Мельком глянул на Language FAQ и бегло ознакомился с основными чертами языка в 65-страничной спецификации языка. И, честно говоря, не уверен в том, что руки дойдут до более тщательного его изучения – разве что после его официального релиза (хотя бы в виде стабильной Beta-версии или Release Candidate).

Как водится, язык мультипарадигменный. Со сборкой мусора, с элементами функционального программирования (включая алгебраические типы и паттерн-матчинг), с каким-то подобием ОО и пр., даже с возможностью писать собственные плагины для компилятора и тем самым расширять синтаксис языка. По современной традиции в язык встроена поддержка агентного программирования и каналов для обмена данными между параллельно работающими сущностями (тасками).

Из описания языка меня зацепило вот что – в Rust нет конструкции catch. Т.е. если кто-то внутри таска выбросил сигнал (я так понял, что это аналог исключения), то все – весь таск убивается. А другие таски могут разве что определить, что он умер.

Неоднозначное, на мой взгляд, решение. Ведь это означает, что какие-то операции (тот же ввод-вывод) нужно будет делать на кодах возврата. Открыли файл – проверили код возврата, записали N байт, опять проверили. Не нравится мне это. Впрочем, есть шансы, что я чего-то недопонял.

Да, еще одна мысль меня терзает. Вот в Go сделали каналы. В Rust сделали. А я думаю, что такие вещи на уровне универсального языка – не есть правильно и хорошо. Каналы и агенты должны реализовываться библиотеками. Тогда можно будет создавать разнообразные инструменты, как универсальные, так и заточенные под конкретную прикладную область. Скажем есть в ACE свой механизм Reactor-ов и Proactor-ов, а в Boost-е есть asio. А у нас в SObjectizer есть агенты, которые прячут сам факт использования Reactor-ов от программиста. А есть еще и libevent. Можно выбирать.

Конечно, свобода выбора имеет и недостатки. Но вот взглянем на Erlang – там механизм взаимодействия процессов является частью языка. Ну и? Где текстовые редакторы, написанные на Erlang? Где какой-нибудь grep на Erlang-е? Правильно, не под то Erlang со своими процессами заточен. Вот так и Go с Rust-ом можно заточить по какой-нибудь определенный server side и ничего на них больше не напишешь. В отличии от C++ или Java.

Так что не торкнул  меня сам факт наличия Rust-а. Ну разрабатывают его, ну и пусть разрабатывают. Будем посмотреть.

четверг, 8 июля 2010 г.

[life.sport.darts] Техники броска в дартс

Один интересный момент в дартсе – отсутствие какой-то одной общепринятой техники броска. В общем-то есть традиционные рекомендации: не следует двигать корпус при броске, бросающая рука должна разгибаться только в вертикальной плоскости, после выброса дротика рука должна как бы сопровождать его и т.д.

Но вот в том, что касается стойки и даже способов держания дротика – здесь полный разброд и шатание. Главный принцип, как я понял – это наличие результата. Удобно вам держать дротик двумя пальцами – держите двумя, удобно стоять боком к мишени и сосредотачивать вес практически полностью на одной опорной ноге – так и стойте. Нет, как я понимаю, одной правильной техники для всех, поэтому нужно искать и совершенствовать свой собственный способ игры.

Очень интересно в этом смысле посмотреть за игрой мастеров дартса. Вот как бросают Phil Taylor и Simon Whitlock (видео интересно еще и тем, что здесь супермастера играют чуть лучше меня ;) ):

А вот как играют Raymond van Barneveld и James Wade:

Это Mark Dudbridge и Wayne Mardle:

А вот играют легенды прошлых лет, John Lowe и Eric Bristow:

Просмотры подобных роликов не проходят бесследно :) Так, насмотревшись на Марка Дудбриджа, я начал подкручивать дротик в момент замаха (хотя я уже не уверен в том, что это хорошо). А сейчас пытаюсь бросать из стойки, похожей на стойку Симона Уитлока. В общем, поиск продолжается.

среда, 7 июля 2010 г.

[prog] Вышла версия 5.8.0 библиотеки ACE

Несколько дней назад вышла новая версия библиотеки ACE – 5.8.0. Кроме нескольких исправлений, в ней есть одно нововведение: некая дополнительная библиотека INet, которая сейчас содержит реализации клиентов для протоколов http и ftp. Данная библиотека, однако, находится в начальном состоянии и, как предупреждают разработчики ACE, ее API еще может измениться.

eao197: какой-то on-line документации по этой библиотеки я найти не смог :( В самом дистрибутиве ACE эта библиотека лежит в каталоге ACE_wrappers/protocols/ace/inet

Под катом находится тест из состава ACE, который показывает, как выглядит использование INet.

Скачать эту версию можно отсюда: http://download.dre.vanderbilt.edu/previous_versions/

PS. Сам я пока на 5.8.0 переходить не буду, подожду выхода 5.8.1, релиз которой намечается на начало августа.

вторник, 6 июля 2010 г.

[blog] Похоже, blogger неприятно глючит

Странная штука сегодня творится с blogger-ом. Я по почте получаю комментарии от читателей, а в самом блоге эти комментарии не отображаются – blogger вообще показывает, что у заметок комментариев нет.

Так что я пока вынужден воздержаться от ответов читателям. Подожду, посмотрю, что будет дальше.

Приношу свои извинения за то, что не могу вовремя отвечать :(

[prog.flame] В продолжение вчерашней темы – мой ответ экспертам board.rt.mipt.ru

Моя вчерашняя заметка “Вот за что мне не нравится C++” засветилась на форуме board.rt.mipt.ru. Как и следовало ожидать, тамошними экспертами я был объявлен тупым и криворуким.

Понятное дело, слышать, что у тебя “такой маленький” неприятно даже в том случае, если это далеко не так. Так что запасаемся линейками и приступаем :)

Для начала я объясню со слайдами, в чем была проблема у Стива Хьюстона с классом ACE_INET_Addr, поскольку один из высказавшихся экспертов, очевидно, не понял о чем речь. В классе ACE_INET_Addr имеется такой код (из ACE 5.6.8):

/**
* @class ACE_INET_Addr
*
* @brief Defines a C++ wrapper facade for the Internet domain address
* family format.
 */
class ACE_Export ACE_INET_Addr : public ACE_Addr
{
  ...
private:
  /// Underlying representation.
  /// This union uses the knowledge that the two structures share the
  /// first member, sa_family (as all sockaddr structures do).
  union
  {
    sockaddr_in  in4_;
#if defined (ACE_HAS_IPV6)
    sockaddr_in6 in6_;
#endif /* ACE_HAS_IPV6 */
  } inet_addr_;
};

Обратить внимание следует на поле inet_addr_, которое является объединением. Если при компиляции определен символ ACE_HAS_IPV6, то объединение включает и sockaddr_in, и sockaddr_in6, а размер inet_addr_ определяется размером sockaddr_in6 (т.к. эта структура больше). Если же ACE_HAS_IPV6 при компиляции не определен, то inet_addr_ содержит только sockaddr_in.

Так вот проблема Стива Хьюстона была в том, что сама библиотека ACE была скомпилирована с ACE_HAS_IPV6, т.к. ACE предполагала, что sizeof(inet_addr_) == sizeof(sockaddr_in6). Однако, прикладная программа была скомпилирована без ACE_HAS_IPV6. Соответственно, в программе sizeof(inet_addr_) == sizeof(sockaddr_in). Т.е. в программе под объект ACE_INET_Addr на стеке отводилось меньше места, чем на это расчитывала библиотека ACE. Поэтому происходило следующее: в программе на стеке отводилось место (23 байта под inet_addr_), далее запускался конструктор ACE_INET_Addr (запускался код из ACE), конструктор ACE_INET_Addr обнулял содержимое inet_addr_ – но не 23 байта, а 28 байт! Отсюда и грабли, на поиск которых было потрачено 5 часов рабочего времени.

А теперь парочка примеров того, как можно отгрести на ровном месте проблемы с C++ кодом, если чуть ошибиться с опциями компиляции для разных файлов. Ответов я давать не буду, пусть желающие попробуют предсказать результат с ходу. Примеры проверялись на Visual C++ 2003 и Visual C++ 2008. Архив с примерами находится здесь. Для компиляции достаточно зайти в нужный подкаталог и запустить в нем nmake.

Исходные тексты примеров так же можно увидеть под катом. Но сначала я хочу сказать, при чем здесь язык C++, ведь упомянутые ошибки не относятся напрямую к языку C++. Да, это не проблемы языка C++, это проблемы инструмента под названием C++. А вот как раз этот инструмент оказывается очень хрупким и чувствительным к настройкам компилятора и линкера. Вполне может быть, что аналогичными проблемами страдают и другие инструменты (тот же C, может быть Ada и, вполне возможно, Eiffel, т.к. он компилируется через C-шное представление). Но меня волнуют именно проблемы C++.

понедельник, 5 июля 2010 г.

[prog.flame] Вот за что мне не нравится C++

…так это за “хрупкость” результатов компиляции и линковки. Приведу пару примеров, с которыми довелось столкнуться в конце прошлой недели.

В первом эпизоде довелось поучаствовать самому. Подошел ко мне коллега, который пожаловался, что пару дней долбется с проблемой возникновения Access Violation буквально на ровном месте. Он занимался доработкой чужой программы, изменил одну из структур и в месте, которое раньше прекрасно работало, стал выскакивать злобный AV. Причем отладчик указывал в какие-то дебри реализации STL-я и понять, почему мы туда попали не представлялось возможным.

Когда я покурил проблемные исходники, мне стало понятно, что в самом месте возникновения AV проблемы нет, там нормальный корректный код. Значит, раз ошибка таки возникает, эта ошибка является наведенной – где-то в другом месте происходит “расстрел” памяти, а затем здесь его последствия “аукаются”.

С не самым лучшим настроением, предвкушая длительное бодание с чужим кодом я сделал себе checkout исходников из репозитория, скомпилировал, запустил… И ошибки не возникло.

Мой коллега пользовался Visual Studio, в том числе и для компиляции. Полного cleanup-а проекта он давно не делал. Что там в результате многих компиляций и инкрементальной линковки получалось – фиг знает. В конце-концов что-то срослось не так и на ровном месте возникал AV. Зато полный cleanup с последующим полным build-ом устранил проблему совсем.

Сам-то я еще в середине 90-х выработал для себя простое правило – если в большом C++ проекте начинают выскакивать непонятные глюки, самое первое, что нужно сделать – выполнить полный rebuild (т.е. сначала хардкорный cleanup, затем build с “чистого листа”). Не буду утверждать, что это помогало в 50% случаев, но помогало часто.

О втором эпизоде я прочитал в блоге Стива Хьюстона (одного из главных разработчиков библиотеки ACE и C++ной реализации AMQP в Apache-вском проекте). Перескажу вкратце: человек убил 5 часов рабочего времени на поиск проблемы с использованием ACE_INET_Addr. Оказалось, что сама библиотека ACE компилировалась с опцией ACE_HAS_IP6 и в ее представлении структуры ACE_INET_Addr было отведено место для sockaddr_in6, а вот приложение – без опции ACE_HAS_IP6, соответственно, в ее представлении структуры ACE_INET_Addr структуры sockaddr_in6 не было. Понятное дело, что когда экземпляр ACE_INET_Addr попадал из кода приложения в код ACE, приходил маленький пушной зверек.

Когда я был молодым, полным сил и задора, мне казалось, что все это херня. Что в правильных руках и с правильными инструментами ничего подобного не происходит, а С++ – самый лучший язык программирования :/

Теперь же, когда я узнаю, что мы теряем дни в поисках подобных проблем, остается только произнести про себя какую-нибудь банальность, вроде шит хаппенс или се-ля-ви. Ну и в очередной раз вспомнить, какой объем унаследованного C++ кода находится в нашем распоряжении, что бы очередной позыв переписать все на какой-нибудь Scala задохнулся в зародыше :(

В качестве же сухого остатка могу рассказать о простых вещах, которые я использую, чтобы не сталкиваться с подобными проблемами или минимизировать их эффект:

  • простой и надежный способ компиляции C++ных проектов. Всякие интеллектуальные инкрементальные компиляции и линковки – в топку. Лучше потерять несколько минут ожидая завершения компиляции, чем тратить часы на поиск несуществующих проблем;
  • компиляция всех сторонних библиотек вместе со своим проектом. Чтобы избежать проблем различий в настройках компилятора. Еще очень желательно, чтобы система компиляции могла проверять согласованность параметров, а так же могла распространять обязательные параметры одного подпроекта на все использующие его компоненты. Отчасти Mxx_ru это умеет, поэтому-то я Mxx_ru в свое время написал и использую его каждый день;
  • я компилирую сразу в release-режиме. Отлаживаюсь только с помощью отладочных печатей и тщательного обдумывания происходящего. Только в особо злостных случаях делаю полный rebuild в debug-режиме, чтобы воспользоваться отладчиком. После чего опять полный rebuild в release-режиме.

воскресенье, 4 июля 2010 г.