К. Касперски - Техника оптимизации программ, Эффективное использование памяти (1127752), страница 4
Текст из файла (страница 4)
Напротив, основной интерес представляют алгоритмы, увеличивающие производительность от двух до десяти (а то и более!) раз и при этом не требующие от программиста сколь-нибудь значительных усилий. И такие алгоритмы, пускай это покажется удивительным, в природе все-таки есть; Введение 0 оптимизация должна допускать безболезненное внесение изменений. Достаточно многие техники оптимизации "умерщвляют" программу, поскольку даже незначительная модификация оптимизированного кода "срубает" всю оптимизацию на корню. И пускай все переменные аккуратно распределены по регистрам, пускай тщательно распараллелен микрокод и задействованы все функциональные устройства процессора„пускай скорость работы программы не увеличить и на такт, а ее размер не сократить и на байт! Все это не в силах компенсировать утрату гибкости и жизнеспособности программы.
Поэтому мы будем говорить о тех, и только тех приемах оптимизации, которые безболезненно переносят даже кардинальную перестройку структуры программы. Во всяком случае, грамотную перестройку. (Понятное дело, что "кривые" руки угробят что угодно — против лома нет приема). Согласитесь, что такая постановка вопроса очень многое меняет. Теперь никто не сможет заявить, что, дескать, лучше прикупить более мощный процессор, чем тратить усилия на оптимизацию. Ключевой момент предлагаемой концепции состоит в том, что никаких усилий на оптимизацию тратить как раз не надо.
Ну, почти не надо, — как минимум вам придется прочесть эту книжку, а это какие-никакие, а все-таки усилия. Другой вопрос, что данная книга предлагает более или менее универсальные и вполне законченные решения, не требующие индивидуальной подгонки под каждую решаемую задачу. Это одна из тех редких книг, если вообще не уникальная книга, которая описывает переносимую оптимизацию на системном уровне и при этом ухитряется не прибегать к ассемблеру.
Все остальные книги подобного рода требуют свободного владения ассемблером от читателя. Впрочем, совсем уж без ассемблера обойтись не удалось, особенно в частях, посвященных технике профилировки и алгоритмам машинной оптимизации. Тем не менее, весь код подробно комментирован и его без труда поймет даже прикладной программист, доселе даже не державший отладчика в руках. Ассемблер, кстати, — это довольно "простая штука", но его легче показать, чем описать. И в заключение этого раздела позвольте привести еще одну цитату: "Я программирую, чтобы решать проблемы, и обнаружил, что определенные мысли блокируют все остальные мысли и творческие цели, которые у меня есть.
Зто мысли об эффективности в то время, когда я пытаюсь решить проблему. йзне кажется, что гораздо логичнее концентрироваться полностью на проблеме, решить ее, а затем творчески запрограммировать, затем, если решение медленное Гчто затрудняет работу с ним), то..." Сагу Мазов. Введение О чем и для кого предназначена эта книга Настоящая книга описывает устройство и механизмы взаимодействия различных компонентов компьютера и рассказывает об эффективных приемах программирования и технике оптимизации программ, как на уровне машинного кода, так и на уровне структур данных. Она ориентирована на прикладных программистов, владеющих !хотя бы в минимальном объеме) языком С, а также на системных программистов, знающих ассемблер. Описываемые техники не привязаны ни к какому конкретному языку, и знание С требуется лишь для чтения исходных текстов примеров, приведенных в книге.
В не меньшей степени "Техника оптимизации" будет интересна и лицам, занимающимся сборкой и настройкой компьютеров, поскольку подробно описывает устройство "железа" и разбирает "узкие места" распространенных моделей комплектующих. В основу данной книги положена уникальная информация и методики, разработанные лично автором. Информация, почерпнутая из технической документации производителей комплектующих, операционных систем и компиляторов, тщательно проверена, в результате чего обнаружено большое количество ошибок, на которые и обращается внимание читателя (тем не менее, автор не гарантирует отсутствие вторичных и "привнесенных" ошибок в самой книге). Материал книги в основном ориентирован на микропроцессоры АМ0 Агп!оп и 1пге1 Репгыпп-П, Реп!!цгп-П1 и Реп!!опт-4, но местами описываются и более ранние процессоры.
Семь китов оптимизации или жизненный цикл оптимизации Часто программист (даже высококвалифицированный!), обнаружив профилировщиком "узкие" места в программе, автоматически принимает решение о переносе соответствующих функций на ассемблер. А напрасно! Как мы еще убедимся !см, разд. "Смертельная схватка: ассемолер кп компилятор" главы 4), разница в производительности между ручной и машинной оптимизацией в подавляющем большинстве случаев крайне мала. Очень может статься так, что улучшать уже будет нечего, — за исключением мелких, "косметических" огрехов, результат работы компилятора идеален и никакие старания не увеличат производительность более чем на 3 — 5%. Печально, если это обстоятельство выясняется лишь после переноса одной или не- Введение скольких таких функций на ассемблер.
Потрачено время, затрачены силы и все это впустую. Обидно, да? Прежде, чем приступать к ручной оптимизации, не мешало бы выяснить: насколько неоптимален код, сгенерированный компилятором„и оценить имеющийся резерв производительности. Но не стоит бросаться в другую крайность и полагать, что компилятор всегда генерирует оптимальный или близкий к тому код. Отнюдь! Все зависит от того, насколько хорошо вычислительный алгоритм ложится в контекст языка высокого уровня. Некоторые задачи решаются одной машинной инструкцией, но целой группой команд на языках С и Рааса!.
Наивно надеяться, что компилятор поймет физический смысл компилируемой программы и догадается заменить эту группу инструкций одной машинной командой. Нет! Он будет тупо транслировать каждую инструкцию в одну или (чаще всего) несколько машинных команд, со всеми вытекающими отсюда последствиями. Назовем ряд правил оптимизации. Правило( Прежде, чем оптимизировать код, обязательно следует иметь надежно работающий неоптимнзированпый вариант или "...рпг аП уопг еййв 1п опе Ьавйе1, айег нзаИнй ваге тйа( уоп'че Ьпйт а геайу *йоооь Ьавйе1" ('Ьрежде, чем класть все яйца в одну корзину — убедись, что ты сплел действительно хорошую корзиму').
Таким образом прежде, чем приступать к оптимизации программы, убедись, что программа вообще-то работает. Создание оптимизированного кода "на ходу", по мере написания программы, невозможно! Такова уж специфика планирования команд — внесение даже малейших изменений в алгоритм практически всегда оборачивается кардинальными переделками кода. Потому, приступайте к оптимизации только после тренировки на "кошках", — языке высокого уровня. Это поможет пояснить все неясности и "темные" места алгоритма. К тому же, при появлении ошибок в программе подозрение всегда падает именно на оптимизированные участки кода (оптимизированный код за редкими исключениями крайне ненагляден и чрезвычайно трудно читаем, потому его отладка — дело непростое), — вот тут-то и спасает "отлаженная кошка".
Если после замены оптимизированного кода на неоптимизированный ошибки исчезнут, значит, и в самом деле виноват оптимизированный код. Ну, а если нет, то ищите их где-нибудь в другом месте. Правило П Помните, что основой прирост оптимизации дает не учет особенностей системы, а алгоритмическая оптимизация. Никакая, даже самая "ручная" оптимизация не позволит существенно увеличить эффективность пузырьковой сор- Введение тировки или процедуры линейного поиска.
Правильное планирование команд и прочие программистские трюки ускорят программу в лучшем случае в несколько раз. Переход к быстрой сортировке (г1ц)сх зогг) и двоичному поиску сократят время обработки данных как минимум на порядок, — как бы криво не был написан программный код. Поэтому, если ваша программа выполняется слишком медленно, лучше поищите более эффективные математические алгоритмы, а не выжимайте из изначально плохого алгоритма скорость по капле. Правило!11 Не путайте оптимизацию кода н ассемблерную реализацию. Обнаружив профилировщиком узкие места в программе, не торопитесь переписывать их на ассемблер. Сначала убедитесь, что все возможное для увеличения быстродействия кода в рамках языка высокого уровня уже сделано.