Техника оптимизации под линуха

       

Удаление лишних обращений к памяти


Компиляторы стремятся размещать переменные в регистрах, избегая "дорогостоящих" операций обращения к памяти. Взять хотя бы такой код: "i=*p+c; b = *p - d;". Очевидно, что второе обращение к *p лишнее и компиляторы поступают так: t =*p; i = t+c; b = t-d, при этом неявно полагается, что содержимое ячейки *p не изменяется никаким внешним кодом, в противном случае оптимизация будет носить диверсионно-разрушительный характер. Что если переменная используется для обмена данными/синхронизации нескольких потоков? Что если какой-то драйвер возвращает через нее результат своей работы? Наконец, что если мы хотим получить исключение по обращению к странице памяти? Для усмирения оптимизатора во всех этих случаях необходимо объявлять переменную как volatile

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

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

Вот, например:

f(int *a, int *b)

{

       int x;

       x = *a + *b;  // сложение содержимого двух ячеек

       *b = 0x69;    // изменение ячейки *b, адрес которой не известен компилятору

       x += *a;      // нет гарантии что запись в ячейку *b

не изменила ячейку *a

}



Содержание раздела