К. Касперски - Техника оптимизации программ, Эффективное использование памяти (1127752), страница 5
Текст из файла (страница 5)
В частности, следует избавиться от прожорливых арифметических операций (особенно обращая внимание на целочисленное деление и взятие остатка), свести к минимуму ветвления, развернуть циклы с малым количеством итераций, в крайнем случае, попробуйте сменить компилятор (как было показано выше — качество компиляторов очень разнится друг от друга). Если же и после этого вы останетесь недовольны результатом тогда: Правило 1Ч Прежде, чем порываться переписывать программу на ассемблер, изучите ассемблерный листинг компилятора на предмет оценки его совершенства.
Возможно, в неудовлетворительной производительности кода виноват не компилятор, а непосредственно сам процессор или подсистема памяти, например. Особенно это касается наукоемких приложений, жадных до математических расчетов и графических пакетов, нуждаюшихся в больших объемах памяти. Наивно думать, что перенос программы на ассемблер увеличит пропускную способность памяти или, скажем, заставит процессор вычислять синус угла быстрее.
Получив ассемблерный листинг откомпилированной программы (для М1сгозой Чцша1 С++, например, это осушествляется посредством ключа угл), бегло просмотрите его на предмет поиска явных ляпов и откровенно глупых конструкций наподобие: моу клх, 1ввх1~моч [квх1, влх. Обычно гораздо проще не писать ассемблерную реализацию с чистого листа, а вычишать уже сгенерированный компилятором код. Это требует гораздо меньше времени, а результат дает ничуть не худший.
Правило Ч Если ассемблерный листинг, выданный компилятором, идеален, но программа без видимых причин все равно исполняется медленно, не отчаивайтесь, а за- Введение грузите ее в дизассемблер. Как уже отмечалось выше, оптимизаторы крайне неаккуратно подходят к выравниванию переходов и кладут их куда "глюк" на душу положит. Наибольшая производительность достигается при выравнивании переходов по адресам, кратным шестнадцати, и будет уж совсем хорошо, если все тело цикла целиком поместится в одну кэш-линейку (т, е. 32 байта).
Впрочем, мы отвлеклись. Техника оптимизации машинного кода — тема совершенно другого разговора. Обратитесь к документации, распространяемой производителями процессоров — (пге! и АМР. Правило Ч! Если существующие команды цроцессора позволяют реализовать ваш алгоритм проще и эффективнее, — вот тогда действительно, "тяпиув" для храбрости пивка, забросьте компилятор на полку и приступайте к ассемблерной реализации с чистого листа.
Однако с такой ситуацией приходится встречаться крайне редко, и к тому же не стоит забывать, что вы — не на необитаемом острове. Вокруг вас — огромное количество высокопроизводительных, тщательно отлаженных и великолепно оптимизированных библиотек. Так зачем же изобретать велосипед, если можно купить готовый? Правило ЧИ Если уж взялись писать на ассемблере, пишите максимально "красиво" и без излишнего трюкачества. Да, недокументированные возможности, нетрадиционные стили программирования, "черная магия" — все это безумно интересно и увлекательно, но плохо переносимо, непонятно окружающим (в том числе и себе самому после возращения к исходному коду десятилетней давности) и вообще несет в себе массу проблем. Автор этих строк неоднократно обжигался на своих же собственных трюках, причем самое обидное, что трюки эти были вызваны отнюдь не "производственной необходимостью", а ну, скажем так, "любовью к искусству".
За любовь же, как известно, всегда приходится платить. Не повторяйте чужих ошибок! Не брезгуйте комментариями и непременно помешайте все ассемблерные функции в отдельный модуль. Никаких ассемблерных вставок — они практически непереносимы и создают очень много проблем при портированииз приложений на другие платформы или даже при переходе на другой компилятор. Единственная предметная область, не только оправдывающая, но, прямо скажем, провоцирующая ассемблерные извращения, это — защита программ, но это уже тема совсем другого разговора.
з Портирование — перенос программного обеспечения с одной среды "обитания" на другую (от англ. рогйея), Введение Распространенные заблуждения Оптимизация овеяна многочисленными заблуждениями, которые вызывают снисходительную улыбку у профессионалов, но зачастую необратимо уродуют психику и калечат мировоззрение новичков. Я думаю, профессионалы не обидятся на меня за то, что я потратил несколько страниц книги, чтобы их развеять (естественно, имею в виду заблуждения, а ие самих профессионалов).
Заблуждение! "За меня все оптимизирует мой компилятор!" Вера в могущество компиляторов в своем корне абсолютно безосновательна. Хороший оптимизирующий компилятор по большому счету может похвастаться лишь своим умением эффективно транслировать грамотно спроектированный код, т. е. если он не сильно ухудшает исходную программу, то уже только за это его разработчикам следует сказать "спасибо". Изначально "кривой" код не исправит никакой компилятор, и оптимизирующий — в том числе. Не сваливайте все заботы по эффективности на транслятор! Лучше постарайтесь в меру своих сил и возможностей ему помогать. Как именно помогать — это тема отдельного большого разговора, которому планируется посвятить третью книгу настоящей серии.
Краткий же перечень возможностей машинной оптимизации содержится в гл. 4данной книги. Заблуждение В "Максимальная эффективность достижима лишь при программировании на чистом ассемблере, но отнюдь не на языке высокого уровня" Перенос программы на ассемблер только в исключительных случаях увеличивает ее эффективность. При трансляции качественного исходного кода оптимизирующие компиляторы отстают от идеальной ручной оптимизации не более чем на !Π— 20% Конечно, это весьма ощутимая величина, но все же не настолько, чтобы оправдать трудоемкость программирования на чистом ассемблере! Подробнее о сравнении качества машинной и ручной оптимизации см.
равд. "Смертельная схватка: ассемблер гз компилятор" главы 4. Заблуждение В! "Человек, в отличие от оптимизирующего компилятора, просто физически не способен учесть все архитектурные особенности процессора" Вообще говоря, кроме компиляторов, разрабатываемых !пге!, никакие другие компиляторы не умеют генерировать оптимально спланированный с точки Введение зрения микроархитектуры процессора код!.
Несколькими страницами далее !см. разд. ГПракпгнческий сеанс профилироеки с )гТнпе" главы 1) вы сами сможете убедиться в этом, а пока же просто поверьте автору на слово. Тем ие менее, современные процессоры с одной стороны достаточно умны и самостоятельно оптимизируют переданный им на выполнение код. С другой стороны, оптимального кода для всех процессоров все равно не существует и архитектурные особенности процессоров Р-П, Р-4, АМР Кб и АГЫоп отличаются друг от друга столь разительно, что все позывы к ручной оптимизации гибнут прямо на корню. Исключение составляет небольшой круг весьма специфичных задач (например, парольных переборщиков), требования которых к производительности более чем критичны.
В этом случае ручная оптимизация действительно "рвет" компилятор, как Тузик грелку. Заблуждение1Ч "Процессоры семейства хвб — полный «отстой», вот на РовгегРС, например, действительно есть место, где развернуться!" Как гласит народная мудрость "Хорошо там — где нас нет". Сам я, правда, ничего не оптимизирую под РошегРС, но знаком с людьми, разрабатываю- щими под него оптимизирующие компиляторы. И могу сказать, что они далеко не в восторге от его "закидонов", коих у него, поверьте уж, предоста- точно.
! Под оптимальностью обычно понимается глобальный экстремум некоторой оценочной функции. При оптимизации по скорости ищут абсолютный минимум числа тактов. Очевидно, этот минимум зависит от входных данных. В лучшем случае компилятору можно передать данные тестового прогона (так называемый ргой1ег Гееоьас1~). На основании этих данных компилятор может более аккуратно присвоить частоты выполнения разным последовательностям инструкций, не более того.
Компиляторы 1п!е! ии коим образом не генерируют оптимального кода, Исходя из определения, оптимальная по скорости программа ие может быть переписана с сохранением смысла так, что начнет исполняться быстрее. Мие приходилось переписывать вручную порожденный этим компилятором код так, что ои становился быстрее. На мой взгляд, было бы правильнее сказать, что компилятор !ше! является единственным из рассматриваемых автором оптимизирующих компиляторов, который способен воспринимать обратную связь от тестовых прогонов и выполнять глобальное распределение регистров.