Павел Ильин Межпроцедурные анализы и оптимизации.

Презентация:



Advertisements
Похожие презентации
МАССИВЫ 4 Определение 4 Описание 4 Обращение к элементам массива 4 Связь массивов с указателями 4 Примеры программ.
Advertisements

О конформности Си-программ Михаил Посыпкин ИСП РАН.
МГУ имени Ломоносова, механико-математический факультет, кафедра вычислительной математики Исследование проблемы переполнения буферов в программах Пучков.
Распределение памяти. Динамическое выделение памяти.
Функции Функция – именованная последовательность описаний и операторов, выполняющая некоторое действие. Может иметь параметры и возвращать значение. Функция.
Языки и методы программирования Преподаватель – доцент каф. ИТиМПИ Кузнецова Е.М. Лекция 7.
Преобразования типов В языке C/C++ имеется несколько операций преобразования типов. Они используются в случае, если переменная одного типа должна рассматриваться.
Лекция 6. Способы адресации в микропроцессорных системах.
М.Ю. Харламов, ВНУ им. В.Даля, Оптимизация программы Оптимизация программы это обработка, связанная с переупорядочиванием и из­менением операций.
ТЕОРИЯ И ПРАКТИКА МНОГОПОТОЧНОГО ПРОГРАММИРОВАНИЯ Тема 15 Методика разработки и анализа неблокирующих алгоритмов. Д.ф.-м.н., профессор А.Г. Тормасов Базовая.
Лекция 14 Динамические данные. Виды памяти Существует три вида памяти: статическая, стековая и динамическая. Статическая память выделяется еще до начала.
Подпрограммы 1.Принцип модульности 2.Область действия переменных 3.Параметры подпрограмм 4.Модули.
Основы информатики Массивы. Указатели. Заикин Олег Сергеевич
ФГОБУ ВПО "СибГУТИ" Кафедра вычислительных систем УКАЗАТЕЛИ Преподаватель: Доцент Кафедры ВС, к.т.н. Поляков Артем Юрьевич © Кафедра вычислительных систем.
Физические модели баз данных Файловые структуры, используемые для хранения информации в базах данных.
Лекция 9 Функции. Массивы-параметры функции Передача массива в функцию Пример: void array_enter(int a[], int size) { int i; for (i = 0; i < size; i++)
Элементы ЯПВУ. УКАЗАТЕЛИ. C / С++Pascal Вся динамическая память в Pascal это сплошной массив байтов (куча). Адрес начала кучи храниться в переменной HeapOrg,
Лекция 1 Классификация С++. Парадигмы программирования Императивная Функциональная Декларативная (логическая) Инструкция 1 Инструкция 2 Инструкция 3 Инструкция.
Основы информатики Лекция. Массивы. Указатели. Заикин Олег Сергеевич
Инструкции C++ Условная инструкция Формат: if (условие) оператор; else оператор; Пример: if (i!=0) { if (j) j++; if(k) k++; else if(p) k--; } else i--;
Транксрипт:

Павел Ильин Межпроцедурные анализы и оптимизации

Содержание Межпроцедурные оптимизации: Граф вызовов процедур ( call graph ) Подстановка процедур ( inline ) Частичная подстановка ( partial inline & outlining) Пропагация констант, диапазонов, выравнивая, указателей и алиасов ( constant, range, alignment, points-to, aliases propagation ) Клонирование процедур ( cloning) Замена стандартных процедур ( replacing) Хвостовая рекурсия ( tail recursion) Оптимизации доступа в память ( memory optimizations) Межпроцедурные анализы указателей: Результаты анализов: указатели и алиасы, свойства may- и must-point-to Неинициализированные указатели и неадресные значения Чувствительность к потоку управления Чувствительность к вызывающему контексту Модель обработки динамической памяти и составных объектов Учет языковых типов, требование компиляции всей программы Эффективный анализ на основе свойства транзитивности Точный анализ на основе ЧТФ Agenda

Граф вызовов процедур Граф вызовов – мультиграф, вершины – процедуры. Вершины proc1, proc2 соединены ориентированном ребром (proc1, proc2 ), если процедура proc1 вызывается из proc2. Трудности при построении: Раздельная компиляция Различные вызовы одной и той же процедуры ( пометка точки вызова) Вызовы по косвенности и рекурсивные вызовы Глобальные метки и нелокальные переходы Свойства графов: Динамический и статический Чувствительность к контексту ( fully context-sensitive context-insensive) Оптимизации на графе вызовов: Удаление невызывающихся процедур ( «мертвый код») Пропагация свойства процедур невозврата управления ( abort, exit, longjmp) для переноса операции через операцию вызова Планирование на межпроцедурном уровне по «холодным» и «горячим» регионам – не просаживать буфер инструкций Анализ указателей – уточнение графа вызовов, превращение косвенных вызовов в прямые Call graph

Подстановка процедур Подстановка процедуры – замена вызова процедуры на копию ее кода, связывание формальных параметров с фактическими, возвращаемых значений с переменными, в который происходит запись этих значений. Inline

Подстановка процедур Трудности: Несовпадение числа формальных и фактических параметров ( функции с переменным числом параметров, нотация Керниган-Риччи) Нелокальные метки в вызывающем контексте – простановка глобальных меток в точках подстановки процедуры Коррекция профильной информации и результатов анализов Подстановка рекурсивной процедуры Плюсы: Избавляемся от накладных расходов на вызов Специфицируем контекст для проведения локальных оптимизаций ( оптимизация циклов) Минусы: Рост кода Просадка кеша инструкций Давление на регистры Утяжеление процедуры – увеличение времени работы компилятора – неэффективный анализ Поддержка в языках программирования - директива inline Inline

Подстановка процедур Схемы подстановки – разный обход графа вызовов: Начиная с main берем процедуру и подставляем в нее все вызываемые процедуры, которые могут быть подставлены. Начиная с процедур, не содержащих вызовы ( листовых) подставляем их в процедуры, откуда они вызываются и могут быть подставлены. Оптимизация листовых процедур (Leaf-Routine Optimization) упрощение пролога и эпилога вызова процедуры за счет того, что внутри не содержится вызовов. Эвристики inline: Профильная информация ( чем больше процедура вызывается, тем больше она годится для подстановки) Размер подставляемого кода ( чем меньше процедура, тем больше она годится для подстановки) Процедуры внутри цикла надо подставлять для расширение возможностей оптимизации Если некоторые параметры процедуры константы, то надо подставлять для повышения эффективности оптимизаций благодаря пропагации констант Inline

Частичная подстановка Частичная подстановка ( partial inline) - процедуры с большим размером кода, не подходящим по эвристике для подстановки, но содержащие значительную вероятную часть. Подготовка ( outlining ): В соответствии с профилем выделяется наиболее вероятная часть процедуры Выходы из вероятной части стягиваются в одну точку, в которой строится вызов новой процедуры называемой хвостовой ( tail proc), содержащей маловероятные остатки Outlining полезен для уменьшения размера процедур Partial inline and outlining Proc { } Proc { } tail_proc { } вер. часть маловер. остатки Вер. часть Call tail_proc маловер. остатки

Частичная подстановка Подстановка: Если у процедуры есть разрезанная копия, то подставляем вероятную часть и оставляем вызов хвостовой части Процедура с большим размером кода, но при вызове она специфицируется параметрами до небольшого размера – необходим пропагатор. Partial inline and outlining

Пропагатор Пропагация констант ( constant propagation) – пропагирует статически известные константные значения по представлению. Propagator

Пропагатор Пропагация выравниваний определяет для каждой операции доступа в память выровненность на определенное значение ( фортран ). Пропагация указателей определяет к каким именно объектам в памяти обращаются операции доступа в память. Пропагация алиасов определяет могут ли две операции доступа в память работать с одним фрагментом. Пропагация диапазонов определяет интервал или набор возможно принимаемых значений объектами программы С помощью этих анализов возможно специфициовать поведение процедуры для опеределенных вызывающих контекстов – провести клонирование процедур. Propagator

Клонирование процедур Клон – спецификация процедуры для определенного вызывающего контекста Клонирование подставляет вместо вызова процедуры вызов ее клона, соответствующего приходящим в эту точку вызова контекстам После клонирования становится возможно подстановка. Cloning Множество вызывающих контекстов Множество вызывающих контекстов 1 Процедура f Множество вызывающих контекстов n Клон f1 Клон fn

Клонирование процедур Cloning

Замена стандартных процедур Replacing – замена вызова стандартной функции с некоторыми параметрами на эквивалентный код Это позволяет сделать затем подстановку или вообще избавиться от вызова. Для замены требуется условие доверия к стандартным библиотекам, errno и т.д. Replacing

Хвостовая рекурсия Хвостовая рекурсия – преобразование рекурсии в цикл заменой рекурсивного вызова процедуры переходом к первой операции. Для замены необходимо: После рекурсивного вызова сразу следует выход из процедуры При наличии профиля вызовов > 0 Если глубина >= 2, то уменьшаем ее с помощью подстановки. Tail recursion

Оптимизации работы с памятью Оптимизация размещения данных в памяти замена выделения многомерного массива на одномерный. Разбор шаблона – динамическое выделение многомерного массива Замена его на выделение одномерного массива Замена работы с многомерным массивом на одномерный Расположение исходных данных по профильной информации Шаблон выделения памяти: a = malloc( n1*sizeof(data**)); for ( i = 0; i < n1; i++ ) { a[i] = malloc( n2*sizeof(data*)); for ( j = 0; j < n2; j++ ) a[i][j] = malloc( n3*sizeof(data)); } Memory optimizations

Оптимизации работы с памятью Memory optimizations

Оптимизации работы с памятью Memory optimizations

Оптимизации работы с памятью Memory optimizations

Оптимизации работы с памятью Достаточные условия для применения: Выделение памяти через стандартные функции malloc, calloc, memalign Не было взятия адреса на объекты, содержащие данные (в примере static double ***a) или указатели на данные ( исключая возможно стандартные безобидные функции scanf(%d,&a[i][j][k] ) Отслежены все обращения к данным ( для глобальных данных необходим анализ в режиме компиляции всей программы) Плюсы: Замена нескольких операций доступа в память на одну ( блочную) Улучшение работы индексного анализа, разрыв зависимостей Дополнительное переупорядочивание данных позволяет оптимизировать работу с памятью Переупорядочивание данных ( Reordering transformations) Транспонирование матрицы ( разместить в памяти по столбцам) Массив структур -> структуру массивов ( AoS -> SoA ) Разрезание и переупорядочивание структур ( Structure splitting and reordering) Memory optimizations

Анализы указателей и алиасов Результаты анализов: анализ указателей – на какие области памяти указывает каждый указатель в программе анализ алиасов – для любых пар указателей ответ указывают ли они на одну область памяти Анализ указателей => анализ алиасов Анализ алиасов => анализ указателей ? p = &x; q = &p; *q = &y; p ->{x,y}, q->{p},,, Points-to and aliases analysis

Анализы may-point-to и must-point-to Свойства результатов: анализ may-point-to – указатель может указывать на некоторую область памяти анализ must-point-to – указатель обязательно указывает на некоторую область памяти May-Point-to and must- point-to analysis

Неинициализированные указатели и неадресные значения Разыменование неинициализированного указателя 1)Некорректная семантика – завершение анализа 2)Разыменование в правой части присваивания ( только чтение). Тогда считаем обращения к объекту в левой части ( в который пишем) конфликтуют со всеми обращениями в память 3)Разыменование в левоей части присваивания – некорректная семантика и завершение 4)Игнорируем. Считаем, что результат разыменования не будет использован как адрес для обращения в память, иначе ошибка исполнения.

Неинициализированные указатели и неадресные значения Неадресные значения ( что считать инициализацией указателя) 1)Любое присваивание в указатель – инициализация 2)Присваивание только адресных значений – адреса объектов программы и возвращаемый процедурами выделения памяти

Чувствительность к потоку управления Учитывает или нет поток управления внутри анализируемых процедур ( flow-sensitive и flow-insensitive ) Увеличивает точность анализа Существенно увеличивает расходы на память Замедляет работу анализа Позволяет затирать в точке постдоминирующего присваивания предыдущие значения указателя – свойство сильного обновления ( strong update )

Чувствительность к вызывающему контексту Разделение информации ( вызывающий контекст), приходящей в процедуру по разным путям исполнения ( сontext-sensitive ) Нахождение нереализуемых путей ( путь, который никогда не может возникнуть в процессе исполнения программы - unrealized paths problem)

Чувствительность к вызывающему контексту Вызывающий контекст однозначно определяется путем в графе вызовов Разные пути могут давать идентичные контексты, но в общем случае число различных контекстов – число всех путей к процедуре из main – экспонента от числа процедур программы Если есть рекурсивные циклы - число путей потенциально бесконечно Необходимо объединять информацию, приходяющую из разных вызывающих контекстов Объединять всю информацию – не чувствительный к контексту Различать контексты по точкам вызова процедур ( на примере для g этого не достаточно) Клонирование процедур и граф активаций программы

Модель обработки динамической памяти 1)Вся динамическая память - один объект 2)Создавать уникальный объект динамической памяти по точке выделения 3)Путь в графе вызовов определяет объект – эскпонента 4)Некоторый начальный отрезок пути с эвристический длиной

Модель обработки динамической памяти Эвристически распознавать выделение памяти ( newnode – выделение памяти)

Обработка составных объектов Различать элементы составных объектов или рассматривать как единое целое Множество локализаций – подмножество целочисленной прямой, задается парой Для однозначности s != 0 и 0

Обработка составных объектов Соотвествие языковых типов и множества локализаций Языковой типВыражениеМножество локализаций объекта type *ppp struct {type *F;}rr.Fr type *a[]a[i]a type *p;*(p+X)p struct {type *F[];} rr.F[i]r struct {type *F;} a[]a[i].Fa Примечание: f – смещение поля F от начала структуры, s – размер элемента массива

Обработка составных объектов Некорректное использование union

Учет языковых типов Учет типа для операций доступа в память Область памяти, независимо от типа, может содержат указатель любого типа – слаботипизированные языки C/C++ Строгое следование языковым типам – не обработать многие реальные программы Использовать часть ограничений из стандарта языка – например позволять обращаться к int[] c помощью char *, но запрещать доступ по указателю на процедуру или константую строку. Использовать информацию о типе для эвристик – например через формальные параметры типа указатель ждать передачи указателей соответствующего типа.

Требование компиляции всей программы Необходимо наличие для анализа всей программы, за исключением возможно стандартных библиотек ( флаг доверия к библиотекам) Динамически линкуемые библиотеки Помодульная компиляция – анализу необходим предполагать, что любая глобальная переменная может быть модифицированна, любая функция может быть вызвана с неизвестными параметрами

Пример эффективного анализа Анализ на основе свойства транзитивности Для отношения «алиасить» добавляется свойство транзитивности: если и, то. За один проход по представлению происходит сбор информации об алиасах и объединение объектов в соответствии с введенным отношением. Транзитивность увеличивает скорость и уменьшает точность. Результаты – информация об алиасах May-aliased анализ Не чувствителен к управлению Не чувствителен к контексту Динамическую память различает по точкам вызова Элементы составных объектов не различаются Языковые типа не использует Требуется компиляция в режиме вся программа

Пример точного анализа Анализ на основе ЧТФ Трасферная функция процедуры определена для всех вызывающих контекстов, результат - измененный процедурой вызывающий контекст. ( a ) Частичная трасферная функция определена не для всех возможных вызывающих контекстов. Обобщение одной ЧТФ на все вызывающие контектсты и получение таким образом ТФ - моновариантный анализ ( b ) Построение нескольких ЧТФ, определенных в совокупности на всех вызывающих контекстах - поливариантный анализ ( с )

Анализ на основе ЧТФ Идея абстрактной интерпритации – начиная с main итерационно собирается информация о значении указателей и завершается, когда значения указателей в main перестают меняться. Встречаем вызов, построение ЧТФ текущей процедуры приостанаваливается и переходим к анализу вызвынной процедуры ( построению новой или обобщению уже имеющейся ЧТФ), затем продолжается построение ЧТФ текущей процедуры. Эвристики – число ЧТФ, алгоритм сравнения контекстов, обощение области определения ЧТФ. Эффективность точность.

Анализ на основе ЧТФ Пример Как формализовать контекст с точки зрения интересующего нас свойства указывать?

Анализ на основе ЧТФ Чтобы задать область определения ТФ используем points-to функции p->{x,y} p->{y} 1-й и 2-й контекст одинаковые, как это отразить? Пространстро имен ( name space) для каждой ЧТФ: Локальные блоки – не зависящие от вызывающего контекста ( формальные параметры, локальные переменные, динамически выделяемая память) Нелокальные блоки – существуют в вызвающем контексте ( глобальные переменные, объекты вызывающей процедуры) Block binding function – связывает нелокальные блоки в вызывающем и вызываемом контексте

Анализ на основе ЧТФ Начальная points-to функция для main Начальная и конечная points-to функция для f в точке вызова S1 В начале процедуры перезаписываем значение *p, потому на что указыает b0 нас не интересует

Анализ на основе ЧТФ Начальная и конечная points-to функция для f в точках вызова S3 пунктиром анализ определяет, что при записи в *p, записали в *r Конечная points-to функция для main

Анализ на основе ЧТФ Блоки создаем только когда встречаем реальное разыменование указателя, т.е. записываем информацию не в виде p есть указатель на b0, а p c начальным значением

Анализ на основе ЧТФ Неявные вызовы – включаем в область определения ЧТФ таблицу с указателями на функции, которые потенциально могут быть вызваны. Добавляем только в случае реального вызова.

Анализ на основе ЧТФ Обработка рекурсии

Общая схема анализов Эффективный анализ + оценка сложности программы Преобразования упрощающие контекст по результатам эффективного анализа Эвристики необходимости более точного анализа Точный анализ