Оптимизация запросов СУБД
- 1 year ago
- 0
- 0
Межпроцедурная оптимизация ( англ. I nter p rocedural O ptimization, IPO ), или полнопрограммная оптимизация программ ( англ. whole program optimization ) — оптимизация компилятора , которая использует глобальный анализ потока управления и затрагивает множество процедур, даже находящихся в разных модулях, за счёт чего может достигаться существенный прирост быстродействия.
С ростом объёма программ разработчики стали делать свой код всё более удобочитаемым и повторно используемым . Зачастую это приводит к тому, что процедуры становятся предельно общими, в то время как в конкретной программе можно обойтись и частным случаем. Задача межпроцедурной оптимизации — именно генерация таких частных случаев.
Межпроцедурная оптимизация выполняется компилятором автоматически (иногда с указанием специальных директив). Её активация может приводить к существенному увеличению времени компиляции. К компиляторам, умеющим выполнять указанную оптимизацию, относятся MLton и MLKit для Standard ML , для Scheme , JHC для Haskell , Intel C++ Compiler .
Пройдя по коду, компилятор убеждается, что один из параметров всегда константа, и уничтожает его.
void DoSomething(Object* aObj, int aParam)
{
if (aObj==NULL)
throw logic_error("aObj==NULL");
cout << "DoSomething(" << aObj->name() << "," << aParam << ")" << endl;
}
int main()
{
Object obj1, obj2;
DoSomething(&obj1, 1);
DoSomething(&obj2, 1);
return 0;
}
void DoSomething(Object* aObj)
{
if (aObj==NULL)
throw logic_error("aObj==NULL");
cout << "DoSomething(" << aObj->name() << "," << 1 << ")" << endl;
}
int main()
{
Object obj1, obj2;
DoSomething(&obj1);
DoSomething(&obj2);
return 0;
}
Здесь компилятор убеждается, что все реально выполняющиеся виртуальные вызовы ведут к вызову одной и той же функции. Вместо того, чтобы обращаться к таблице виртуальных методов , компилятор делает прямой вызов функции.
В том же примере, если
Object::name()
— виртуальный метод, оптимизированная функция будет выглядеть так.
void DoSomething(Object* aObj)
{
if (aObj==NULL)
throw logic_error("aObj==NULL");
cout << "DoSomething(" << Object::name(aObj) << "," << 1 << ")" << endl;
}
После удаления получится:
void DoSomething(Object* aObj)
{
cout << "DoSomething(" << Object::name(aObj) << "," << 1 << ")" << endl;
}
Заодно может происходить чистка таблиц виртуальных методов .
Если функция используется однократно, она напрямую включается в то место, из которого она вызывается.
Небольшие функции также можно напрямую включать в вызывающий код.
Многие языки программирования (
Паскаль
,
Java
,
D
) не имеют
ключевого слова
inline
, и решение инлайнировать функцию принимается оптимизатором (в случае
Java
—
обфускатором
).
inline int DoSomething(int aParam)
{
return aParam * aParam;
}
int main()
{
int x = 2;
int y = 3;
cout << x << "^2=" << DoSomething(x) << ", " << y << "^2=" << DoSomething(y) << endl;
return 0;
}
int main()
{
int x = 2;
int y = 3;
cout << x << "^2=" << x*x << ", " << y << "^2=" << y*y << endl;
return 0;
}