Вскоре после того, как компилятор "задышал" и приобрел относительную стабильность, мы стали систематически проводить его профилирование. GNU'шная программа gprof выдавала длинные таблицы временных затрат отдельных функций, по этим таблицам мы рисовали огромные, на несколько листов, графы реальных взаимосвязей модулей, пытаясь найти резервы быстродействия. Первый же анализ показал, что около 40% времени тратится на операции со строками и библиотечные функции ввода-вывода. Сначала это показалось естественным — любая идентификация именованного объекта в программе предполагает сравнение имен. Поиск имени в таблицах — одна из базовых операций в любом компиляторе, и даже используя технику хеширования, избежать прямого литерального сравнения идентификаторов невозможно. Однако цифра показалась нам все же чрезмерно большой. Исправить положение без разрушения компилятора было крайне сложно, так как всевозможные операции с именами буквально пронизывали все модули. Это не являлось проектной ошибкой — полностью локализовать работу с именами невозможно, так как сама семантика языка определяет необходимость оперировать с именами практически на всех стадиях компиляции.

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

Точно по такой же схеме обошелся с компилятором мой коллега. Он "вынул" из него старую схему хранения имен и заменил ее на усложненную, но более эффективную. Ключевой момент новой схемы состоял в обеспечении присутствия каждого имени в семантических таблицах в единственном экземпляре. Тогда вместо сравнения литеральных изображений имен достаточно было сравнивать указатели на эти представления. Алгоритмы модулей, использующих операции с именами, никак не изменились, однако в некоторых местах пришлось заменить тип IDENT, представляющий "старый" идентификатор в таблицах, заменить на xIDENT — прямой указатель на единственную копию данного имени. Эту операцию можно было бы сделать одной командой контекстной замены, но никакой редактор не смог бы разобраться, где именно следовало ее производить, а где — оставить по-старому… В очередной раз мы "руками" перещупали весь компилятор. После четырех дней непрерывного труда компилятор разогнался на 25% (наглядная стоимость литеральных сравнений строк в большой программе)!

Фрагмент модуля с усовершенствованной версией обработки имен с тех пор украшает комментарий:

/* Krotoff is a _very_ clever guy! */

Товарища не похвалишь, так и он тебя не похвалит.