Wednesday, March 17, 2010

Некоторые трюки при использовании GDB

Небольшое собрание трюков, которые могут помочь при отладке с использованием GDB. Не претендует на сенсационность, но должно быть полезно для тех, кто только начинает знакомиться с этим замечательным инструментом. Итак, начнём:

Печать содержимого STL контейнеров

Основные способы собраны здесь, но я бы хотел остановиться на наиоболее универсальном способе - gdb-stl-views(нужно добавить в ~/.gdbinit). Он будет работать не только в самых новых версиях, а и в уже устаревших (это является важным фактором для тех, кто не может обновиться). Примеры использования:
(gdb) plist some_list
List size = list_size
List type = std::list<element_type, std::allocator<element_type> >
Соответственно, для того, чтобы распечатать весь список нужно использовать:
(gdb) plist some_list element_type
elem[0]: $i = ...
...
elem[list_size - 1]: $i = ...
List size = list_size
А теперь интересные моменты:
  • Если внутри контейнера хранится умный указатель, то часто для упрощения вывода можно в качестве element_type указать просто указатель (зависит от того, какой умный указатель вы используете. Большая часть из них при reinterpret_cast к указателю даст осмысленный результат). Например, вместо
    plist some_list smart_ptr<elem_type>
    использовать
    plist some_list elem_type*
  • Если вы активно используете пространства имён, element_type скорее всего будет доступен только с полным указанием пространств имён, например NS1::NS2::element_type. Интересной особенностью GDB является то, что он не воспринимает NS1::NS2::element_type* как тип. Обойти эту проблему можно заключив имя типа в одинарные кавычки: 'NS1::NS2::element_type'*
  • GDB иногда игнорирует using namespace. Поэтому лучше просто полностью указывать имя типа со всеми пространствами имён
  • Чем новее у вас версия GDB, тем лучше он работает с пространствами имён. Если есть возможность - поставьте GDB 7.0 и выше

Вывод строк

Если вы активно работаете с разными типами строк, с разным размером символов, то вам пригодится следующий совет. Чтобы вывести строку, которую не желает выводить print, можно использовать:
  • Команду просмотра памяти x. Например,
    (gdb) x/16s some_char_ptr
    для вывода 16 первых символов в символьном виде
  • Можно добавить вот такую функцию в .gdbinit:
    define wchar_print
    echo "

    set $i = 0
    while (1 == 1)
    set $c = (char)(($arg0)[$i++])
    if ($c == '\0')
    loop_break
    end
    printf "%c", $c
    end

    echo "

    end
    Использовать так:
    (gdb) wchar_print some_char_ptr
    Однообразно выводит std::string, std::wstring, различные двухбайтные строки. Естественно, конвертация к ASCII строке приводит к потере информации, однако в большинстве случаев это не так важно

Step Out

Самый короткий совет. Step Out делается командой fin или finish. Это почему-то один из самых распространённых вопросов.


И the last but not the least: в последнее время я довольно редко пишу в этот блог. Одна из причин тому - для небольших спонтанных записей я веду микроблог. Вторая - банальная нехватка времени. Однако не спешите отписываться: в записной книжке скопилось множество интересных статей, советов и идей. Постараюсь возобновить более-менее равномерное наполнение этого блога.

P.S. Для вывода на экран Qt строк можно использовать вот такое:
define printqstring
printf "(QString)0x%x (length=%i): \"",&$arg0,$arg0.d->size
set $i=0
while $i < $arg0.d->size
set $c=$arg0.d->data[$i++]
if $c < 32 || $c > 127
printf "\\u0x%04x", $c
else
printf "%c", (char)$c
end
end
printf "\"\n"
end

Monday, February 1, 2010

Краткий отчёт о PyCamp

Не далее как в прошлую субботу, 30 января 2010, в Киеве состоялась конференция PyCamp Kyiv, основной темой которой был язык Python и сопутствующие технологии. Мне повезло там побывать, и я получил огромное удовольствие от конференции.

Доклады

В основном, доклады были довольно интересными. Ниже представлены некоторые претензии/отзывы по докладам, а также оценка качества повествования/слайдов:
  • Александр Шигин "Почему Python - тормоз и как заставить его меньше тормозить" - неплохой доклад о том, какие конструкции в Python тормозят сильнее, чем другие. Для многих информация из доклада может показаться очевидной, но для меня она оказалась довольно полезной - позволила кое-как классифицировать разрознённые знания по этой теме. Качество повествования-3+, качество слайдов-5.
  • Юрий Юревич "Рецепты декораторов" - очень короткий и довольно малоинформативный доклад о том, что такое декораторы в Python. Несмотря на хорошие слайды(на 5) и доклад(на 4+)
  • Дмитрий Кожевин "Программирование на нервах" - отличный развлекательный доклад на тему управления проектами. Он небольшой и веселый, поэтому смотреть в видеозаписи обязательно. Качество доклада - 5, качество слайдов - 3.
  • Михаил Кашкин "Работа с хранилищем данных в Google App Engine, отличия от реляционной модели" - доклад сочетает в себе общий обзор Datastore и описание некоторых особенностей. Доклад, в принципе, неплохой, но неполный. После него осталось очень много вопросов. Качество слайдов - 5, качество повествования - 4.
  • Александр Соловьев "Redis: Дикий Запад баз данных" - хороший доклад про сверх-быструю key-value db. Удачно выбранная тема в данном случае на 80% определила успех доклада. Качество повествования - 5, качество слайдов - 5
  • Андрей Светлов "Безопасная разработка ПО. Результат длинного пути и множества набитых шишек" - доклад о том, как важно использовать тесты, системы автоматической сборки и прочие вспомогательные тулзы. Довольно длинно, в основном по местам давно обглоданным. К тому же для многих тема "Тестировать или не тестировать" уже далеко не так остра, как была пару лет назад. Качество повествования - 4, качество слайдов - 4.
  • Владимир Пузанов, Владимир Кириллов "Расширение и встраивание Python" - обзорный доклад об интерпретаторах Python, методах расширения стандартной функциональности и связывание с другими ЯП. Было весьма интересно, а продемонстрированный в конце хак нахожу очень приятным и довольно юзабельным. Качество повествования - 4+, качество слайдов - 3.
  • Андрей Мишковский "Использование Python в ГИС" - неплохой обзорный доклад о средствах и библиотеках для создания ГИС на Python. Хотя я бы с большим удовольствием послушал о том, как создаются ГИС, а не с помощью чего(эту информацию можно получить и в Google). Качество повествования - 5, качество слайдов - 5.
  • Сергей Кириллов "WebSockets в Twisted" - неплохой вводный доклад на тему "Что такое WebSockets?". Тема не очень сложная и была полностью раскрыта. Качество повествования - 5, качество слайдов - 5.
  • Александр Бельченко "Интернационализация и локализация Python-приложений с использованием gettext" - подробный доклад об использовании gettext для локализации GUI приложений на Python. Большую часть информации из доклада можно получить при чтении документации, но докладчик также обозначил множество интересных и полезных моментов. Качество повествования - 4+, качество слайдов - 5.
  • Иван Моргун "Работа с платежными системами в Django (PayPal, WebMoney)" - излишне подробный доклад, практически пересказ документации. Доклад можно было существенно порезать и он от этого стал бы более привлекательным. Качество повествования - 3+, качество слайдов - 3+.
  • Дмитрий Жемеров "PyCharm – новая python IDE от JetBrains" - весьма любопытная презентация новой коммерческой IDE для Python. Выглядит весьма многообещающе, но то, что оно написано на Java, а также будет в будущем стоить $100, слегка портит впечатление. Качество повествования - 5, качество слайдов :) - 5

Организация

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

Заключение

Жду видео. Побольше бы таких конференций, хороших и разных!

Sunday, September 27, 2009

Мини-отчёт об участии в GCJ

GCJ(Google Code Jam) - контест по спортивному программированию, который проводит всем известная компания Google. Контест не командный, международный, проводится в онлайн.
В этому году участвовал в первый раз, основные результаты таковы: остановился на втором раунде, в третий не прошёл.

Впечатления

Сумбурные. Участие в ICFPC и в Sapka рождает совсем другие эмоции. GCJ более напряженный, задачи значительно меньше по объему, но труднее, временные рамки куда жестче. Однако задачи GCJ отличаются и от тех, что встречаются на ACMовских олимпиадах. Большинство задач действительно имеют очень короткие и очень красивые решения, каждую из них действительно можно решить за отведенное время, если уловить какую-то важную мысль.

Выводы

  • Неожиданно для себя обнаружил доказательство тезиса "Разные ЯП - для разных задач". Решал задачи на Python(основной язык), Haskell и С++ - действительно, иногда тот или иной язык куда лучше подходил для решения определенной задачи
  • Фан можно получать и от простых задачек, не обязательно рулить спутниками или писать AI для bombermanа. Зря я почти забросил теорию - теперь сыплюсь на стандартных алгоритмах и мне очень стыдно
  • Нужно обязательно участвовать в следующих GCJ. Он совсем не напрягает и занимает куда меньше времени, чем многодневные командные состязания

Интересная ссылкa

Недавно мне подбросили ссылку на еще один контест - Hugi Size Coding Competition Series(hugi-compo), который кардинально отличается от всех, в которых я доселе участвовал. Именно этим он и привлекателен, хоть я и не обладаю достаточной квалификацией для удачных выступлений(контест посвящен ассемблерной оптимизации). Возможно, кого-нибудь заинтересует такое нестандартное соревнование. Спасибо за внимание!

Saturday, July 11, 2009

Сказ о том, как Python С++ обогнал

Я всегда защищаю С++, когда приверженцы других языков ругают его за невыразительный синтаксис, чрезмерную сложность или раздутость, потому что, по-моему мнению, на С++ можно писать красиво, и особенно в этом помогают различные высокоуровневые конструкции из стандартной библиотеки.
В одном из споров в c_plus_plus@c.j.r речь зашла о том, какой же из языков лучше - простой С или всё же С++? В качестве одного из аргументов я предложил провести эксперимент - сколько времени понадобится для решения простой задачи: из stdin считываются строки текста, и после этого в обратном порядке записываются в stdout, т.е., первая строка в stdin становится последней в stdout. Длина строк не ограничена, поэтому для решения ее на С понадобится выделять и перевыделять память, от этого код на С разбухнет, что станет наглядной демонстрацией превосходства высокоуровневых конструкций С++. Более того, я предположил, что код на С++ может быть даже производительней кода на С, написанного без дополнительного профилирования - ведь контейнеры С++ выделяют память так, чтобы reallocate происходил реже. Пример кода на С++, написан за пару минут для демонстрации:

#include <iostream>
#include <string>
#include <vector>

int main() {
std::vector<std::string> v;
while(std::cin)
{
std::string s;
std::getline(std::cin,s);
v.push_back(s);
}
for (std::vector<std::string>::reverse_iterator it = v.rbegin();it!=v.rend();++it)
{
std::cout<<*it<<"\n";
}
}
Как видите, код далеко не оптимален, однако мне хотелось показать, что даже такое решение лучше, чем код на С.
Тут же захотелось проверить, а как другие языки справятся с этой задачей. Например,однострочник на Ruby:
$stdin.readlines.reverse.join.display
Когда я протестировал его на небольших файлах, С++ решение оказалось быстрее решения на Ruby в десятки раз, что меня нисколько не удивило. Однако для чистоты эксперимента я решил увеличить размер файла. Я сгенерировал файл в 100 строк общим размером ~600mb(исходник на Python):
open("/tmp/z.txt",'w').write((''.join(map(str,xrange(1000000)))+'\n')*100
Результаты тестирования на нём были просто поразительны:
ruby 1.8.6 (2009-06-08 patchlevel 369) [i686-linux]:
real 0m9.841s
user 0m0.849s
sys 0m7.206s

gcc (GCC) 4.1.2 (Gentoo 4.1.2 p1.3):
real 0m51.902s
user 0m48.682s
sys 0m1.429s
Я тут же решил проверить решение на Python:
import sys
sys.stdout.write('\n'.join(reversed(sys.stdin.readlines())))
Результаты:
Python 2.6.2
real 0m4.855s
user 0m0.913s
sys 0m1.233s
Т.е., еще быстрее, чем ruby (что уже не удивительно ;) ). Просмотрев код на С++, я добавил простейшую оптимизацию, которую изначально добавлять не хотел, чтобы код совсем не был похож на С. Я добавил хранение в векторе указателей, а не строк, что должно было убрать ненужное копирование:
#include <iostream>
#include <string>
#include <vector>

int main() {
std::vector<std::string*> v;
while(std::cin)
{
std::string * s = new std::string();
std::getline(std::cin,*s);
v.push_back(s);
}
for (std::vector<std::string*>::reverse_iterator it = v.rbegin();it!=v.rend();++it)
{
std::cout<<*(*it)<<"\n";
delete *it;
}
}
Но результат всё так же не вдохновляет:
real 0m46.444s
user 0m43.462s
sys 0m1.379s
Назначив ответственным за тормоза std::string, я попытался переписать всё на QString из Qt, которые, по слухам, умеют copy-on-write и вообще быстрые. Наивный код:
#include <iostream>
#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
#include <QtCore/qtextstream.h>
#include <vector>

int main() {
QList<QString> v;
QTextStream st (stdin);
QTextStream sto (stdout);
while(!st.atEnd())
{
v.push_back(st.readLine());
}
QListIterator<QString> it(v);
it.toBack ();
while (it.hasPrevious ())
sto<<it.previous()<<"\n";
}
Однако это решение пожрало все 2 гигабайта моей оперативной памяти и я его остановил, попросив Qt-шников с c_plus_plus@c.j.r помочь с оптимизацией. После нескольких минут получился вот такой код, который использовал уже 1.4 гигабайта оперативки:
#include <iostream>
#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
#include <QtCore/qtextstream.h>

int main ()
{
QList<QByteArray> v;
QTextStream st (stdin);
QTextStream sto (stdout);
int line = 0;
while (!st.atEnd ())
{
std::cerr << "Reading line... " << line++ << std::endl;
v.push_back (qCompress (st.readLine ().toUtf8 (), 9));
}
QListIterator<QByteArray> it (v);
it.toBack ();
while (it.hasPrevious ())
{
std::cerr << "Writing line... " << std::endl;
sto << qUncompress (it.previous ()) << "\n";
sto.flush ();
}
}
Однако он работал еще медленнее, чем на стандартных строках - более двух минут. Для чистоты эксперимента я также написал вариант на Python, который не использовал стандартные join и reversed, а был более похож на код на С++:
import sys
s = sys.stdin.readlines()
for x in xrange(len(s)-1,-1,-1):
sys.stdout.write(s[x]+'\n')
Его результаты:
real 0m2.198s
user 0m0.884s
sys 0m1.190s

Выводы

Если не учитывать опыты с Qt(всё равно ведь хороших результатов добиться не удалось), ни в одном из языков не было использовано каких-либо особых оптимизаций, напротив, были использованы те конструкции высокого уровня, которые предлагает сам язык. И удивительно, что программы на Python и Ruby смогли с большим отрывом обогнать аналогичную программу на С++. Я сам еще не знаю причину этого, и я был бы очень рад, если бы кто-то смог прогнать аналогичные тесты у себя на машине. Однако вне зависимости от причины, такой результат явственно говорит одно - нельзя безоговорочно верить в то, что С++ быстрее интерпретируемых языков, особенно если простейшие высокоуровневые конструкции в них, такие как строки, работают лучше.

P.S.

Я не старался создать идеальные условия для тестирования и не прогонял тесты сотни раз, чтобы получить идеальный результат. Достаточно всего-лишь заметить, что в этом синтетическом тесте Python был в 2-5 раз быстрее Ruby, а Ruby была в 4-5 раз быстрее С++. Спасибо за внимание!

Частичная реабилитация(update)

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

int main() {
std::ifstream fin("/dev/stdin");
std::vector<std::string*> v;
while(fin)
{
std::string * s = new std::string();
std::getline(fin,*s);
v.push_back(s);
}
for (std::vector<std::string*>::reverse_iterator it = v.rbegin();it!=v.rend();++it)
{
std::cout<<*(*it)<<"\n";
delete *it;
}
}

real 0m1.783s
user 0m0.656s
sys 0m1.070s

Т.е., тормозил std::cin. Естественно, это не оправдание, поэтому реабилитация только частичная. Вывод: tools don't kill software. people kill software.

Tuesday, July 7, 2009

Bachelor Thesis in Computer Science. Part 3. Слайды в LaTeX-beamer

Лучше поздно, чем никогда - предлагаю вам обещанную третью часть с описанием того, что есть LaTeX-beamer и как его можно использовать при написании бакалаврской работы.
beamer - класс LaTeX, который позволяет быстро создавать красивые слайды. Если вы не знаете, что это такое или ни разу не пробовали - попробуйте, и вам больше никогда не захочется запускать громоздкие системы WISIWYG для создания слайдов.
Основные достоинства beamer, на которые хотелось бы обратить внимание:

  • Полное разделение оформления и содержания. Сначала пишите текст, а оформление можно сменить в любой момент
  • Очевидный плюс, но забывать о нём нельзя: можно использовать все возможности LaTeX
  • Красивые и удобные темы оформления "из коробки"
  • Широкие возможности в настройке и доводке

Пример применения

Эта статья не задумывалась как учебное пособие по beamer, ее цель - дать представление и заинтересовать. Поэтому сразу перейдём к скриншотам и некоторым советам. Титульная страница, которую любезно сгенерирует вам beamer после заполнения некоторых полей:
Один из слайдов:

Как видите, слайды выглядят весьма привлекательно. К тому же, представьте, что каждый слайд - это всего пара строчек текста. А теперь, как я и обещал, несколько советов подкрепленные кодом:
  • Не пытайтесь изменить шрифт, чтобы вместить на слайд как можно больше информации. Выполненные в PowerPoint с 12pt шрифтом презентации навевают тоску и абсолютно нечитаемы с расстояния в 5-10 метров. Если уж очень нужно разместить на слайде побольше, а количества строк не хватает - используйте двухколоночную вёрстку. Тогда даже большое количество формул может поместиться на один слайд:
    Для верстки в две колонки используйте пакет multicol(на примере вставки изображений в две колонки):
    \usepackage{multicol}
    %%....
    \begin{multicols}{2}
    \begin{figure}[!ht]
    \begin{center}
    \includegraphics[width=\columnwidth]{../img/positioning_slides1}
    \end{center}
    \end{figure}

    \begin{figure}[!ht]
    \begin{center}
    \includegraphics[width=\columnwidth]{../img/positioning_slides2}
    \end{center}
    \end{figure}
    \end{multicols}
  • Создатели тем оформления beamer не подумали, что название может быть длинным и сократить его будет нельзя. Поэтому во многих темах длинные названия не влазят на слайд. Однако это можно исправить - например, использование подправленной темы оформления, которую вы видели на скриншотах:
    \usetheme{Antibes}
    \useinnertheme{rounded}
    \setbeamertemplate{headline}
    {%
    \begin{beamercolorbox}[wd=\paperwidth,ht=6.5ex,dp=1.125ex,%
    leftskip=.3cm,rightskip=.3cm plus1fil]{title in head/foot}
    \usebeamerfont{title in head/foot}\parbox[b]{0.95\paperwidth}{\@title}
    \end{beamercolorbox}
    \begin{beamercolorbox}[wd=\paperwidth,ht=2.5ex,dp=1.125ex,%
    leftskip=.3cm,rightskip=.3cm plus1fil]{section in head/foot}
    \usebeamerfont{section in head/foot}%
    \ifthenelse{\value{page}>1}{\hskip2pt\raise1.9pt\hbox{\vrule width0.4pt height1.875ex\vrule width 5pt height0.4pt}}{}
    \hskip1pt%
    \insertsectionhead
    \end{beamercolorbox}
    \begin{beamercolorbox}[wd=\paperwidth,colsep=1.5pt]{lower separation line head}
    \end{beamercolorbox}
    }


    \setbeamertemplate{footline}
    {%
    \leavevmode%
    \hbox{\begin{beamercolorbox}[wd=.5\paperwidth,ht=2.5ex,dp=1.125ex,leftskip=.3cm plus1fill,rightskip=.3cm]{author in head/foot}%
    \usebeamerfont{author in head/foot}\insertshortauthor
    \end{beamercolorbox}%
    \begin{beamercolorbox}[wd=.5\paperwidth,ht=2.5ex,dp=1.125ex,leftskip=.3cm,rightskip=.3cm plus1fil]{title in head/foot}%
    \usebeamerfont{title in head/foot}Слайд \insertframenumber
    \end{beamercolorbox}}%
    \vskip0pt%
    }
    Этот небольшой сниппет может стать отправной точкой для написания собственных тем оформления - в нём совсем несложно разобраться по названиям команд
  • Скриптованные презентации никому не нужны. Я имею в виду моргающие анимированные слайды со сложной системой переходов, которые можно создать в Microsoft Office или OpenOffice. Для улучшения восприятия достаточно простейших эффектов, которых можно легко добиться в beamer. Единственной полезной вещи, которой может не хватать в beamer по сравнению с PowerPoint и Impress - воспроизведение видео. Однако встроить видео в PDF тоже можно! Пример:
    \usepackage{movie15}
    %%...
    \frame
    {
    \includemovie[externalviewer]{}{}{../vid/mouse_emulation.avi}
    }
    Этот код отводит отдельный слайд под видео. Стоит отметить, что видео можно будет проиграть только в Adobe Reader (я не знаю свободных альтернатив, которые бы поддерживали видео). Также обратите внимание, что я использую внешний плеер. Использование внешнего плеера гарантирует максимальную кросс-платформенность вашего PDF документа

Выводы

Используйте LaTeX, используйте beamer. Забудьте о медленных, неудобных офисных пакетах, полных недостатков и ошибок.

P.S.

Здесь вы можете найти исходники презентации (без изображений и видео)