![]() |
Мне очень запомнилось высказывание Михаила Флёнова в одной из его книг: «Если Вы написали программу, то Вы программист. Но если Ваша программа лучше других, то Вы хакер. Оптимизация — один из способов сделать программу максимально быстрой, эффективной и выделяющейся на фоне остальных».
Так оно и есть. Очень приятно, когда сложная и многофункциональная программа буквально «летает», и хочется убить программиста, когда его небольшая утилита «тормозит» по любому поводу. Первым делом я всегда осуществляю оптимизацию алгоритма. На мой взгляд, именно от алгоритма зависит весь жизненный цикл программы. После оптимизации алгоритма можно попробовать улучшить отдельные функции, небольшие связанные между собой части программы, поиграться с параметрами. Но в конце-концов наступает момент, когда всё кажется вылизанным до последней мелочи и можно считать, что программа оптимизирована. Однако, если Вы используете один из языков высокого уровня, то есть ещё один шаг — низкоуровневая оптимизация. Я расскажу Вам об основах этого нелёгкого, но интереснейшего занятия. В качестве рабочего инструмента я буду использовать язык программирования C++, а конкретнее — компилятор g++. Так как само название «низкоуровневой оптимизации» говорит нам о том, что работать мы будем на уровне языка ассемблера, то стоит заметить, что я использую ОС GNU/Linux, а значит мы будем иметь дело не стандартным синтаксисом INTEL, а с синтаксисом AT&T, немного отличающимся от привычного нам кода, например, в MASM или TASM. Перед константными выражениями в соответствии с правилами синтаксиса AT&T мы будем ставить знак $, перед именами регистров – %, а в командах пересылки на первое место ставится источник, на второе — назначение (в синтаксисе INTEL всё как раз наоборот). Синтаксис AT&T может показаться совершенно непонятным на первый взгляд, а, может быть, даже неуклюжим и глупым. Но лично я считаю его более удобным и совершенным: логичнее указывать источник первее, чем назначение, а обозначение регистров со знаком % и констант со знаком $ в конце-концов делает код более читабельным и простым для восприятия. Кроме того, стоит заметить, что так же я использую архитектуру x86_64, а значит, если Вы работаете в 32-разрядной операционной системе, то в некоторых моментах код для Вашей платформы может немного отличаться от моего. На этом закончим вступительную часть и приступим непосредственно к теме статьи. Общая информация Код на C++ будет переведён компилятором в машинные команды, а значит, скорее всего, может быть переведён в код на языке Assembler. Так оно и есть. Для этого укажите компилятору опцию -S: Код:
g++ test.cpp -SЧем нам может быть полезен код на ассемблере? А тем, что компилятор реализует инструкции «общим случаем», т.е. таким образом, чтобы они работали всегда. Отсюда и идёт некоторая потеря производительности: то тут лишняя инструкция влезла, тот там ещё лишние пять. Давайте сразу рассмотрим пример: [CODE] int main() { for (int i=0; i |
| Время: 12:11 |