Category: it

Category was added automatically. Read all entries about "it".

Особенности кодирования

Занимаясь разработкой своего пета, наконец-то смог четко выделить две особенности, которые (как мне кажется) отличают мой стиль программирования.

Первое. Частый compile/run. Для компактного приложения (например, для юнит-теста) я стараюсь пользовать функцию компиляции проекта и его запуска максимально часто (примерно раз в минуту). При этом запуску подвергается любой успешно собираемый вариант - пусть даже он имеет одни только заглушки и его исполнение гарантированно обрушит программу - я хочу видеть КАК ИМЕННО оно его обрушит? Получу ли я нужную диагностику в протокол, совпадет ли вывод в лог и поведение программы с тем, что я ожидаю. Например, недавно получил pure function call, который бы 98% не случился, если бы я написал чуть больше кода, а не бросил реализацию функции на полпути.

Второе. Перевод ошибок в компайл-тайм. Отлаживал ошибку с порчей хипа, оказалось, что в нужном месте не нажался амперсанд и класс, который не имеет права пользовать copy ctor, вернулся из функции не по ссылке, а по значению. Наверное, большинство программистов заменят MyClass get() на MyClass& get() и успокоятся (ошибка исправлена). Я вместо этого поступаю иначе. Сначала меняю реализацию MyClass - добавляю приватный copy ctor и на всякий случай в него пихаю hard assert с диагностикой "this call is not allowed" (чтобы потом не облажаться еще и во внутренних методах). Потом компилирую программу и получаю желаемую ошибку в compile time. И только после этого исправляю MyClass& get().

А используются ли такие особенности кодирования у вас?

Рецепты отладки. Быстрая ловля Access Violation.

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

О чем тогда шла речь. В случае возникновения access violation (нетипичные случаи не в счет) по адресу падения и карте линкера можно быстро разобраться, в какой именно функции произошло падение приложения. Если еще спасены и cod-файлы, то локализовать место падения можно с точностью до строки.
Разумеется, есть pdb и dbghelp, есть минидамны и множество других "казуальных" решений, которые не требуют включения мозга. Но, во-первых, эти решения занимают дополнительное время для исследования падения, во-вторых, они не всегда применимы. Например, после обработки приложения системой защиты, или в случае, если pdb отсутствует на целевой машине. Кроме того, это обязательно требует передачи дополнительных файлов данных с целевой машины на компьютер разработчика.
В этом смысле MessageBox("Unhandled exception (type: access violation) at 0x0045FB2A") намного оперативнее, и даст нам достаточно информации для первоначального анализа падения.

Collapse )

CRT Extension

Вопрос, который возник в дискуссии в каментах к одной из прошлых записей - по поводу наличия в коде некоторой библиотеки под кодовым названием "CRT Extension". Назначение библиотеки - общие функции, которыми должны пользоваться программисты вместо прямого вызова CRT API, Windows API и так далее. К этим функциям можно отнести: единый центр протоколирования, ассерты, отладочные и heap'овые менеджеры памяти, функции синхронизации и параллелизации вычислений, виртуальную файловую систему, стандартные классы и темплейты и многое другое (список можно расширять или сокращать в зависимости от специфики разработки ПО, поддерживаемых платформ, компиляторов, внутренних стандартов и приемов программирования).

А есть ли у вас в компании CRT-Extension, которым должны пользоваться программисты вместо прямых вызовов?

Poll #1517598 CRT-Extension

Есть ли у вас в компании библиотека типа CRT-Extension?

Есть, пользуемся.
33(64.7%)
Есть, планируем избавиться (если можно, в коментах - почему).
0(0.0%)
Нет, но хочется / планируется.
6(11.8%)
Нет, и не надо.
12(23.5%)

О компиляции /EHsc (часть 2)

В предыдущей части мы рассмотрели компиляцию основного кода с включенной опцией /EHsc. По коментам к предыдущей части - отвечу на справедливый вопрос о замере производительности функций. Итак, для синтетического примера кода с Sample a, b; и func1()/func2() на 100000000 вызовов результаты отличаются примерно на 6% - 980 ms против 920 ms (Core2 Duo 6700 @2.66 MHz). Для примера с Sample a[100] накладных расходов заметно больше - 7597 ms против 4926 ms (разница выполнения - порядка 35%).

Collapse )

Логи, часть четвертая

Логи, часть четвертая.

Последняя часть рассказа про логи - это технические аспекты реализации лог системы - что может быть удачным, а что - нет. И на какие грабли можно наступить в процессе реализации.

Основой для протоколирования в С/С++ может стать макрос, который на вход принимает следующие параметры:
- уровень протоколирования;
- метка сообщения;
- сам текст сообщения;
- имя файла и номер строки, опционально - имя функции;

Collapse )

Логи, часть третья

Мы разобрались, что такое лог-менеджер и что такое уровни протоколирования. В третьей части речь пойдет об анализе логов. Никакая теоретическая подготовительная работа "что и как надо логгировать" не заменят задач по наполнению логов действительно осмысленной информацией. И эта работа должна предшествовать периоду, когда приложение отчуждается от разработчика.

Collapse )

Логи, час вторая

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

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

Collapse )

Логи, часть первая

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

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

Collapse )

Теория ошибок. Нестабильности третьего и четвертого рода.

Развивая тему анализа нестабильностей, которую я начал еще весной (http://ddima.livejournal.com/48573.html и http://ddima.livejournal.com/49288.html), оставалось рассмотреть нестабильности третьего рода - это собственные ошибки функции. То есть когда все наружные условия соблюдены, объект или модуль находятся в правильном состоянии, все переданные аргументы являются правильными, а результат работы функции все равно оказывается некорректным. Но как показала последующая практика, эти нестабильности полезно разделить еще на два независимых вида - это нестабильности, связанные с ошибками алгоритма, непроинициализированными переменными и т.п. (нестабльности третьего рода) и нестабильности, связанные с некорректной обработкой результатов функций (четвертого рода).

Collapse )

Про bubblesort, кеши и оптимизацию программы.

Несколько интересных соображений, навеянных публикациями по dual-pivot quicksort.

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

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

Collapse )