среда, 2 декабря 2009 г.

Игры со временем

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

Не нужно планировать время.

Очень много времени в SCRUM тратится на планирование. Мало того, что мы должны разделить все истории на задачи, мы еще должны, как дураки, оценивать время играя в карты.

Программистам не нужно время. Дайте программисту четко поставленную задачу и не отвлекайте, пока не будет готово.

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

Чтобы программисты могли точно оценивать время - нужен большой опыт. Причем опыт именно в предсказании времени :). Можно прекрасно представлять себе объем работ, но постоянно ошибаться со сроками.

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

И это тоже проблема. Поэтому не надо планировать все задачи сразу.

Если вы планируете внедрять SCRUM - послушайте моего совета. На бумажках нельзя писать абстрактные и неконкретные вещи. Каждая бумажка должна представлять из себя конкретную задачу для одного человека. Не получается чтобы по одной бумажке и программист программировал и тестер тестировал. Не пойдет скрам. Бумажки будут мотаться по доске без видимого результата. Еще раз: конкретная задача для одного человека. Взял, сделал, done, без вариантов!

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

Это чем-то перекликается с GTD Дэвида Аллена. Тем, что все запланировать практически нереально, но первое конкретное действие легко определяется почти всегда (Или фичу нужно сразу вернуть оунеру).

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

В SCRUM проще. Мы разбиваем задачу на работы и прикидываем время выполнения этих работ. Только проблема в том, что если работа неконкретная, то и время выполнения получается неконкретное, и следовательно вряд ли оно будет соблюдено.

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

Но это вовсе не означает что время совершенно не нужно для программистов.

Программирование - процесс творческий. И зачастую связанный с познанием неизведанного. А познание неизведанного - процесс крайне трудно поддающийся планированию. Когда речь идет о неизведанном - разговоры о времени неуместны? Еще как уместны!

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

То есть просто временной лимит. Который, следует заметить, для конкретной работы не просто не нужен - а даже вреден, поскольку вносит лишний нервирующий фактор. Риск неуложиться во время, демотивация, и тд и тп...

Вот где-то такие мысли у меня по поводу agile. Не SCRUM, не Kanban...

PS: Опять давно ничего не писал, мыслей вроде много, а писать - руки не доходят. Как с этим бороться?

среда, 14 октября 2009 г.

KDE3 is dead?

На прошлой неделе в Gentoo размаскировали KDE-4.3 для платформы amd64. При этом, после окончательной стабилизации KDE4, KDE3 будет удалена из репозитория навсегда.

Двоякое ощущение.

С одной стороны дома я уже давно сижу на KDE4.2, дома у меня больше возможностей и желания для экспериментов. С другой стороны KDE4 расстраивает меня своим уходом в красивости. Да мне пофиг красивости, хотя дочке очень нравятся снежинки.

Но правда открытого софта такова, что старая версия уже никому не нужна. И никто не будет возиться с багами, которых там еще много. Ну будем надеяться, что в kde4 помимо красивых плазмоидов у разработчиков дойдут руки и до полезных и нужных вещей, как то работа с сертификатами, получение адресов из LDAP, почему-то все мои проблемы крутятся в основном вокруг kmail? Нет, в kopete очень слабая поддержка jabber. :)

Короче, переехал на kde-4.3.1. Прошарил свою систему, удалил оттуда все, что зависело от qt3, и теперь у меня чистая qt4 система.

Кроме того, я наконец то нашел решение проблемы ntlmaps, терзавшей меня долгое время. Проблема заключается в том, что в один прекрасный момент он перестал запускаться из init скрипта. С консоли запускается, а из init-скрипта ни в какую. Кроме того я давным давно не могу пустить через него firefox - ntlmaps не проксирует запросы почему-то. А иногда еще и проц жрет почем зря - под 100%.

Обнаружилась вполне достойная альтернатива - cntlm , которая пока правда не входит в репозиторий gentoo, но ebuild можно скачать отсюда, чуть чуть поплясать с бубном и все, настало полнейшее счастье, и причем значительно более шустрое.

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

понедельник, 14 сентября 2009 г.

Куда едут мыши?

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

... Я уже собирался было ее выкинуть, но тут меня осенило.

Клавиатура у меня безпроводная, BTC-9116URF. Она совмещает в себе клавиатуру и мышь. Черная штука в правом-верхнем углу - это джойстик.

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

А тем временем Google включил на GoogleCode Mercurial. Я сразу же, как узнал, одно из своих извращений перевел - побаловаться для начала. wiki они отделили, теперь wiki хранится в отдельном репозитории, версии посмотреть можно, а вот как склонировать - могу только догадываться. Возможно, что не предполагает клонирования, только веб-редактирование. Ну и ладно, а то раньше веб-редактирование сильно засоряло репозиторий, я предпочитал редактировать локально.

Кроме того балуюсь с Google Wave, много всяких интересных идей, но о них попозже.

четверг, 10 сентября 2009 г.

The big class unittest

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

Вот и у меня такая же ситуация. Все имена и методы по возможности изменены, все совпадения случайны.

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

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

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

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

Для проверки импорта конфигурации нам вполне неплохо подходит одна функция - назовем ее import_config, хоят по легенде это сделано давным давно, в 19-м веке. :) Эта функция практически не пользуется другими методами класса, кроме функции convert_config, которая в свою очередь дергает несколько мелких функций по конвертации. Все эти функции не зависят от остального содержимого класса... одна беда - они private.

Как говорят великие, такой набор функций - хороший кандидат на извлечение класса по виду ответственности.

Призовем на помощ препроцессор. Поскольку оригинальное описание класса нас совершенно не устраивает - мы его прячем:
namespace hidden {
#include "CBigApp.h"
}
Если мы этого не сделаем, то оно заинклюдится из сишного файла, который мы хотим заинклюдить к себе. Но для начала мы опишем свою версию класса, и делать это мы будем в cьюте, чтобы изолировать его от взаимозависимостей, ведь у нас как бы появятся свои версии функций. Неизбежны проблемы при линковке тестового приложения. Сьют позволяет изолировать эти манипуляции.
BOOST_AUTO_TEST_SUITE(suiteCBiGApp_ImportConfig)

struct CBigApp {
void import_config(const archive &aconfig, const std::string &config_file);
void convert_config(const std::string &config_file, u_int version);
void fix_10_value(const std::string &value &);
void fix_21_value(const std::string &value &);
void fix_22_value(const std::string &value &);
};
Это собственно наше тестовое видение класса. Оно еще не окончательное и нам еще придется с ним повозиться. Прототипы мы без искажений скопировали из CBigApp.h. Ну а теперь подтягиваем реализацию.
#include "Import.cpp"
Может так сложиться, что помимо вышеописанных функций в этом файле реализуются и другие. Тогда и их прототипы необходимо вписать в тестовый класс.

Может быть эта реализация ссылается на другие функции класса, описанные в другом файле. Их тоже можно описать в структуре с необходимой реализацией.
void create_minimal_config(const std::string &)
{ throw logic_error("Не используется"); }
Помимо того наверняка будет так, что в этом файле включаются и другие инклюды - все эти включения, в том числе и стандартные необходимо перенести в начало нашего юниттест-файла, чтобы они первый раз включились в глобальном пространстве имен, второй раз они уже не будут включаться.

После этого у нас появилась возможность вызвать тест...
BOOST_AUTO_TEST_CASE(testImport10)
{
CBigApp app;
BOOST_REQUIRE_NO_THROW(app.import_config(cfg10, "config_file-1.0.cfg"));
::unlink("config_file-1.0.cfg");
}
Да, я знаю, что использовать файловую систему в юниттестах - плохо... но лучше иметь юниттесты, которые используют файловую систему (базы данных, подключения по сети), чем не иметь никаких. Для успокоения совсети их можно назвать функциональными. :)

В тестировании можно пойти дальше, объявив некоторые из методов как virtual, и заменить их в процессе тестирования на что-то удобное для себя:
BOOST_AUTO_TEST_CASE(testImport21)
{
struct inCBigApp : public CBigApp {
virual fix_10_value(const std::string &value &)
{ throw logic_error("Не должен вызываться"); }
} app;
BOOST_REQUIRE_NO_THROW(app.import_config(cfg21, "config_file-2.1.cfg"));
::unlink("config_file-2.1.cfg");
}

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

Вроде пока все.

вторник, 1 сентября 2009 г.

null ostream


Последнее время старательно осваиваю TDD. На работе это пока не используется, но для себя все пишу через тесты. Привычку вырабатываю. :) Купил вот недавно самую дорогую книгу в своей жизни: Шаблоны тестирования xUnit. Рефакторинг кода тестов. Очень познавательная книга. Юнит тестинг без фанатизма. Там в частности написано, что использовать базы данных в тестах можно! Но есть способы лучше. Вообще главная мораль этой книги - что наличие тестов, каких бы то ни было значительно лучше, чем их отсутствие.

Но собственно написать я хотел о другом. Изобретаю консольное приложение. Консольное приложение должно что-то выводить на консоль. Для этого традиционно используется cout. И собственно приложению ничего больше не нужно.

Но когда речь заходит о тестах - cout становится серьезной помехой.

Я выбрал следующий путь решения. Методы, которые что-то выводят, получают в качестве параметра ostream &. Это позволяет в тестах подсунуть вместо cout что-то другое, например ostringstream. И проверить что же собственно вывелось на консоль после вызова метода.

Но иногда тестам и этого не нужно. Бывает нужно передать что нибудь, только чтобы метод им удовлетворился и проглотил. И встает вопрос dummy ostream - потока-заглушки.

Вариант #1 с заглушиванием cout:
std::cout.exceptions(std::ios::goodbit); 
std::cout.setstate(std::ios::failbit);
std::cout << 1; // ignore
... мне совершенно не нравится. Да и для тестов он не очень удобен. Каждый раз глушить и разглушать обратно? Нет, нам нужен объект, наследник ostream, который просто не делает ничего. Сделать так можно. Решение приводить не буду, сошлюсь. Но давайте посмотрим что есть на эту тему в boost. Решение #3, найденное в интернете:
struct null_sink : boost::io::sink {
void write(const char*, std::streamsize) { }
};
typedef boost::io::stream_facade<null_sink> null_ostream;
... сейчас не работает. Не скажу точно когда работало, не важно. Решение #4:
typedef boost::iostreams::stream<boost::iostreams::null_sink> null_ostream;
... работает, но для того, чтобы все было гладко, перед использованием надо вызвать out.open(boost::iostreams::null_sink());, что не совсем удобно. И последнее... onullstream описан в файле boost/test/utils/nullstream.hpp. Одного только не понимаю, почему я не могу создавать его непосредственно при вызове?
int foo(ostream &out);
BOOST_CHECK_EQUAL(foo(onullstream()), 1)
... возвращает ошибку, о том, что нет метода foo, в который можно было бы передать onullstream... но если создать onullstream заранее, то никаких возражений у компилятора не возникает.
onullstream out;
BOOST_CHECK_EQUAL(foo(oot), 1)
... Успешно. Что-то я наверное делаю не так? :)

Unix way?

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

Я могу понять. Всетаки линукс, среда обитания красноглазых линуксоидов... :) Думаете в Windows такого нету?

Озадачился тут намедне вопросом, о том как по умолчанию включить NumLock в Windows XP. Вариант установки в биосе - не очень гибок... хотелось чтобы Windows делал это сам.

Спросил у гугля, недолго думая пошел по первой ссылке на support.microsoft.com, где мне предложили... написать для этой цели скрипт.

PS: Чуть погодя на нашел, какое значение в реестре надо подправить, чтобы все стало как надо. С этой же статьи есть ссылка на другую статью, где все описано правильно. Но ход мыслей нравится...

PPS: Совсем забросил блог, надо как-то исправляться...

вторник, 28 июля 2009 г.

typeinfo for int

Загадочный всетаки компилятор - gcc...

Начать реализацию обработки исключений я решил в простенькой конструкции в коде:

try {
throw 1;
} catch (...) {
}

Но наткнулся на ошибку - undefined reference to `typeinfo for int'.
И вот возникла непонятная задача - как же мне описать typeinfo for int?

gcc очень загадочен. О существовании типа std::type_info он знает безо всяких дополнительных объявлений, что не мешает описать его локально. Но в gcc этот класс чисто базовый, констуктор у него защищен. На это можно было бы наверное наплевать и объявить все по своему, если бы в этом был смысл.

Но необходимый мне typeinfo должен иметь другой тип: __fundamental_type_info. И мне нужно проинициализировать его статически, для чего я долго изголялся с размещающими new в статическом буфере...

Стоит отметить что до сих пор линкер исправно ругался на отсутсвие typeinfo. Но после этого неожиданно начал ругаться на отсутвие 'vtable for __cxxabiv1::__pointer_type_info', странно.

Исследование модуля objdump'ом показало в нем наличие большого количества typeinfo. Стал выяснять - откуда они взялись. И вот ведь загадочный gcc...

Стоит вставить следующий код:

namespace __cxxabiv1 {
class __fundamental_type_info : public std::type_info
{
virtual ~__fundamental_type_info() { }
};
}

Как все необходимые фундаментальные typeinfo появляются как по волшебству. И с размещающим new я изголялся зря. :)

А с исключениями пока еще далеко не все понятно, разбираюсь.

пятница, 24 июля 2009 г.

Исключительная ситуация

Нет, у меня все в порядке, дела идут и жизнь легка. Просто лето и отпуск, и я совершенно забросил свой блог. Но делать так ни в коем случае нельзя. У меня уже был подобный опыт по забрасыванию рассылки comp.soft.prog.asmos на Subscribe.ru, которая находится в дауне до сих пор. Чем больше времени проходит с момента последнего поста, тем проще ничего не писать.

А темой сегодняшнего поста я избрал исключения. Но я не стану расскзывать тривиальные вещи, про то, что исключения из деструктора не бросатся, это и так все знают. Мне вдруг стало интересно как это работает изнутри. Но пока здесь одни вопросы. Разбираться надо.

gcc очень наглый компилятор. Он может спокойно инлайнить функции, даже если используется -O0. Он может нормальные казалось бы вызовы стандартных функций заменять ассемблерными мнемониками. Но с исключениями все обстоит еще сложнее. Стандартный, казалось бы, С++ код превращается в нагромождения непонятных вызовов c которыми я и хотел бы разобраться, чтобы прикрутить исключения к своему ядру.

Правда, тут все зависит от цены, так сказать. Патч для ядра linux, позволяющий использовать C++ с исключениями занимает 600к, в то время как вся моя кроссплатформенная часть (для которой собственно рунтайм и тащится) занимает 200к. Неравноценный получается обмен.

В самом gcc все реализовано максимально переносимо, из за чего, вероятно, трудно все это понять. Большой уровень косвенности. Мне же переносимость в данном случае не нужна, нужна минимальная реализация для конкретной платформы.

Так как же работают исключения? gcc, не смортя на всю свою наглость, конечно молодец. Для корректной отработки деструкторов выделенных в стеке объектов в нем используются так называемые "landing pad", область приземления? или как это правильно перевести. Область приземления располагается в конце каждого программного блока, в котором требуется деинициализация. Причем gcc очеь грамотно задвигает все, что не требуется деинициализировать.

Координаты этих областей перечисленны в "exception handling tables". Эти таблицы формируются компилятором для каждой функции. Хотя может и не для каждой, точно сказать пока не могу.

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

Кстати, именно на функцию __cxa_throw надо ставить брекпоинт для программы, собранной с помощью gcc, если есть желание отловить момент возникновения исключения в отладчике.

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

Стандарт оговаривает и структуры, которые вращаются внутри __cxa_throw и других функций, связанных с исключениями, но для минимальной реализации на это можно забить. Главное - это понять логику разворота стека и связывания функций с соответствующими таблицами прерываний.

Так же для меня является загадкой, почему разработчики gcc так перемешали интерфейсы __cxa* и _Unwind*. Но в недрах реализации они переплетены столь плотно, что разорвать их практически нереально.

Если вдруг кто-то уже разбирался с обработкой исключений в gcc - отзовитесь, у меня много вопросов. :) Хотя постепенно осознание придет, если долго разбираться.

среда, 3 июня 2009 г.

CVCS мертв?

Было время, когда никто не слышал про бранчи. Собственно и система контроля была одна - cvs. Нет две, еще был rcs, но это помоему совсем уж дедушка систем контроля версий.

Но времена меняются очень быстро. Subversion за считанные годы просто похоронил cvs. Да и его скоро отправят на свалку истории...

Несколько дней назад упал savannah.gnu.org. Вследствии отказа RAID-массива содержимое проектных баз было безвозвратно утеряно. Последний нормальный бекап - месячной давности (sic!). Какой же у них рейд, если всеравно все рухнуло?

И вот, бедные владельцы проектов, которых угораздило хранить свои проекты в cvs/svn вынуждены по крохам восстанавливать содержимое баз (буквально с помощью сообщества).

И вот после этого подумаешь - всетаки умные люди не зря придумали DVCS? Скорее бы уже google code поднял меркуриал, я мигрирую.

Собственно для меня история проекта имеет достаточно незначительную ценность. Я просто не знаю зачем она мне может понадобиться. Но прикольно то, что с 2002 года sourceforge бережно хранит мою базу. И только.

В корпоративном плане история несомненно нужна. Хотя бы для того, чтобы выяснить - какой же идиот написал этот код?

Ценность бранчей пока еще ясна не всем, возможно по причине использования устаревших средств, которые с этими самыми бранчами не особо дружат. Я вот точно не знаю, последние версии SourceSafe научились делать бранчи? Perforce например делает вид что умеет это делать, но при этом историю теряет. То есть новый бранч - новая история. И на вопрос из предыдущего абзаца ответить уже не удается.

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

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

Кроме того я привык вносить изменения понемногу, мне просто жизненно необходима собственная база, из которой я мог бы одним чейнджсетом все перенести в базу perforce. Очень хочется такую систему контроля (конечно распределенную), которая умела бы оперировать с чужеродными репозиториями, как со своими. Многого хочу?

А savannah.gnu.org конечно круто опозорился. Все срочно переходят на hg/git на других площадках.

среда, 20 мая 2009 г.

Оптимизация в gcc, факты

При обновлении своей системы наткнулся на неприятный момент, сборка любых KDE компонент начала вдруг запарываться с руганью:
checking if UIC has KDE plugins available... no

Я далек от мысли что у всех все плохо в течении двух недель (где то так у меня впервые не собралась kopete), а Gentoo мантайнеры не чешутся. Поэтому стал разбираться откуда растут ноги.

Стандартной рекоммендацией в такой ситуации считается - пересобрать qt и kde, но легче от этого не стало. Первым делом я конечно заподозрил, что возможно нестабильную kde-3.5.10 сломали, снял все маски - жужжит (c). Потом я подумал, что, возможно, мешается qt:4, снес его, благо он был мне нужен только для perforce gui, можно потерпеть чуток, но счастья опять не наступило. Не наступило счастье и после полной пересборки системы, что уже совсем непонятно, уж полная пересборка должна помочь?

Долго гуглил... Не помню уже где, увидел упоминание про оптимизацию и gcc-4.3.2, а у меня вся система собрана на -Os. Решил поставить стандартный -O2, ради эксперимента. И, о чудо, компиляция компонентов kde прошла. На этом можно было бы остановиться, но кроме осознания факта неработоспособности qt3+kde3 собранных gcc-4.3.2 с опцией -Os, я узнал много нового про gcc, чем не могу не поделится.

Многие наверное будут удивлены, но опция -march=core2 не включает оптимизацию с применением sse*, как принято считать, а всего лишь допускает использование соответствующих встроенных функций. Как убедились, да очень просто:
void test()
{
// sse2 builtin
__builtin_ia32_movnti(0, 0);
}

$ gcc -march=pentium -c test.cpp
test.cpp: In function ‘void test()’:
test.cpp:3: ошибка: нет декларации ‘__builtin_ia32_movnti’ в этой области видимости
$ gcc -march=core2 -c test.cpp
$

Но в то же время использование правильной архитектуры вовсе не стимулирует компилятор к оптимизации кода с применением расширений. Как определили это? да очень просто:
$ gcc -march=core2 -Q --help=target
...
-msse [выключено]
-msse2 [выключено]
-msse3 [выключено]
-msse4 [выключено]
...

Для того чтобы эта оптимизация выполнялась - необходимо явно задавать -mssse3 -mmmx или другие, необходимые для вашей архитектуры.

Надо сказать, что конструкция gcc -Q --help=CLASS очень полезна во всех отношениях. Я раньше этого не знал. В качестве CLASS можно подставлять в частности target, optimisers, warnings тем самым анализируя настройки компилятора с используемыми в вашем проекте опциями.

PS: Одного я только не понимаю, как -Os может столь фатально влиять на связь приложения с библиотекой?

пятница, 27 марта 2009 г.

Ошибка в стандартном инклюде

Интересную ошибку словил на днях...
$ c++ ... -c file.cpp -o file.o
In file included from /usr/include/c++/4.2/bits/basic_ios.h:44,
from /usr/include/c++/4.2/ios:50,
from /usr/include/c++/4.2/ostream:45,
from /usr/include/c++/4.2/iostream:45,
from configuration.h:4,
from wrap.h:15,
from file.cpp:15:
/usr/include/c++/4.2/bits/locale_facets.h:4576: error: template-id 'do_get<>' for 'std::string std::messages::do_get(int, int, int, const std::string&) const' does not match any template declaration
$

Всякие совпадения с реальными файлами являются случайными :)

Причем выяснилось, что если поменять инклюды местами - становится легче. В этом надо разобраться...

Проблема возникает с темплейтами в locale_facets.h.

Для начала прогоню две версии через препроцессор. После долгого сравнения выясняется, что в правильной версии проблемная строка (locale_facets.h:)выглядит так:
 template<>
wstring
messages::do_get(catalog, int, int, const wstring&) const;

А в неправильной:
  template<>
string
messages::do_get(catalog, int, int, const string&) const;

Очень странно, с какого праздника препроцессор в исходном тексте:
  template<>
wstring
messages::do_get(catalog, int, int, const wstring&) const;

заменил wstring на string?

Да очень просто. В одном из инклюдов проекта кто-то очень умный поставил:
#define wstring string

Если все стандартное инклюдится заранее - проблем нету. В противном случае стандартные инклюды тянутся из проектных инклюдов, и в результате ошибка компиляции. И как это называется?

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

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

Вот, как говориться КСCЗБ. Ну и кто написал эту ерунду (это я про define), пойду искать...

вторник, 10 марта 2009 г.

kde4: впечатления

Прошол уже наверное почти месяц, как я решил попробовать kde4. В gentoo оно пока замаскировано но не очень жестко, так, слегка - под ~x86.

Эксперимент я провожу на домашнем компьютере. На рабочем - я работаю, и не могу надолго выводить его из строя. Что в процессе экспериментов случалось уже неоднократно.

Вся система у меня живет под "x86", И все пакеты я размаскирую индивидуально через /etc/portage/package.keywords. После установки kde файл /etc/portage/package.keywords/kde4 насчитывает около 125 строк. Но помимо этого мне пришлось размаскировать xorg-x11, который тоже состоит из весьма большого количества мелких пакетиков.

Раньше я спокойно всю систему держал на ~x86, но потом надоело ходить по краю и я перешел на стабильные версии. Иногда только хочется экстрима, вот как щас. :)

Что-то я уже запамятовал, какая версия kde встала первой, возможно что kde-4.1, но помню точно, что kdm4 сразу не заработал. Он запускался, но экран на седьмой консоли оставался пустым. Первое время приходилось пользоваться kdm3

Кстати про kde3. Обязательно используйте USE="kdeprefix". Без него kde3 сразу же перестал нормально работать, перемешались ресурсы обоих кед. kde3 необходимо обновить до 3.5.10, котороый, в свою очередь, тоже замаскирован (читай - еще 60 строк в /etc/portage/package.keywords/kde3 :) ).

После первого обновления заработал kdm4. Но куда-то делись все иконки из таскбара. Благо у меня их там не очень много, и я легко находил их на ощупь.

Второе обновление захотело новый xorg-server. Удовлетворив все зависимости получил полностью неработающую систему.

Сперва драйвер radeon отказывался запускаться по причине устаревшего abi, полегчало после перекомпиляции.

После этого kdm запустился, но клавиатура с мышью почему-то не оказывают видимого влияния на систему. И сидишь как дурак, перед экраном kdm, не в состоянии ничего сделать. Только reset.

Проанализировав логи сервера обнаружил загадочное сообщение: "AllowEmptyInput default to "yes", keyboard and mouse are disabled", ну что-то около того. Установил переменную в no, клавиатура вернулась на место.

Мышки опять нет, и опять что-то на тему abi... это мы уже проходили.

После этого все стало почти замечательно. Только вот в kde-4.2.1 в правом верхнем углу экрана постоянно крутится измеритель производительности какой-то. В принципе работает исправно, на голом десктопе показывает зеленый, сейчас, в konqueror (я теперь могу писать сообщения в blogger в конкуероре!) - красный. Окошки растягиваются, когда их дергаешь... компизовский чтоль изврат? правда компьютер у меня слабоватый, и в эти моменты индикатор чернеет... Можно конечно со стилями побаловатьcя, эффекты поотключать, но мне не столь важно, kate не тормозит. :)

Дочка один раз что-то нажала, и вокруг курсора появились крутящиеся звездочки. Три веселых крутящихся звездочки. Как она это сделала?

Вот. А в практическим плане можно отметить вот konqueror, который на движке webkit теперь медленно, но верно показывает 85/100 пунктов в acid3 (firefox 3.0.6 показывает 71/100). И пожалуй все. Остальные приложения как были так и остались.

Очень много еще всяких глюков, перечислять не буду.

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

среда, 4 марта 2009 г.

Эффективная работа с унаследованным кодом

Вышла в свет русская версия книги Майкла К. Физерса (Michael Feathers) - "Эффективная работа с унаследованным кодом" (Working Effectively with Legacy Code). Какой я блин шустрый, успел заказать ее на озоне за 854 рубля, хотя сейчас она стоит уже 909...

Не пропустите.



PS: Только что-то Озон не торопится мне её доставлять. Уже два дня как должен был доставить.

PPS: Что-то я совсем расслабился, в блог писать некогда. :)

четверг, 15 января 2009 г.

Хронический аудиал

Что касается женщин, то это чувство сугубо интимное...


Есть некоторые идеомы, считающиеся хорошими. Например считается правильным писать константную часть слева в условии, для того чтобы на операцию '=' вместо '==' ругался компилятор а не конечный пользователь.
if (MIN_ELEMENTS == i) ...
Я долго не мог понять почему мне это так не нравится, и наконец сформулировал для себя ответ на этот вопрос.

Писать так в частности рекоммендует Стив Макконел (Steve McConnell) в книге "Совершенный код". Там же рекоммендуется упорядочивании аргументы в соответствии со значениями на числовой прямой.
if (MIN_ELEMENTS <= i && i <= MAX_ELEMENTS) ...
Очень похожая ситуация, хотя меня она коробит меньше.

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

Может быть такая запись считается удобной и правильной для тех, кто оценивает код визуально. Что же касается меня - я код предпочитаю читать. И читается примерно следующее:
Если MIN_ELENEMTS равен...
Стоп, как может быть константное значение сегодня равно, а завтра не равно? В этом выражении как будто содержится предположение, что MIN_ELEMENTS может измениться.

Кроме того в предыдущей строке мы вероятно работали с i, почему в условии во главу угла возводится совсем другая сущность? А почему собственно мне кажется что первый идентификатор в выражении возведен во главу угла?
i равно чему-то; если i равно MAX_ELEMENTS...
Все последовательно и логично. Но это если код читать... Если воспринимать код целостно, то, возможно, все воспринимается несколько иначе.

Тесты наверное врут, когда определяют меня как кинестатика-визуала. Хотя с другой стороны я люблю чтобы было красиво. Я смотрю на код и целиком. Только когда я смотрю на код - я почему-то не смотрю на идентификаторы, Свысока я разглядываю группы операторов, то есть мыслю уже на другом уровне.

С другой стороны неприятие распределения в соответствии с числовой прямой может связано со складом ума. Предполагаю, что эта запись очень близка к математической, сам то я от математики далек. Может быть людям с математическим складом ума она кажется более естественной чем мне, гуманитарию.

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

PS: Новогодние праздники сильно выбивают из колеи. Ленишься и ничего не хочется делать. Приходится себя заставлять, ну хоть сегодня напиши хоть что нибудь. :)