Введение 3 1 Трансформации индуктивных переменных 13
1.1 Трансформации циклов 14
1.1.1 Автоматическая параллелизация 14
1.1.2 Распознавание циклов-идиом 15
1.1.3 Перестановка циклов 15
1.1.4 Снижение стоимости индуктивных выражений 16
1.1.5 Развертка циклов 17
1.2 Индуктивные переменные и выражения 18
1.2.1 Преобразование типов индуктивных переменных 21
1.2.2 Деление индуктивного выражения на константу 21
1.3 Символьное представление индуктивных выражений 22
1.3.1 С-функция 22
1.3.2 Каноническая форма С-функции 25
1.3.3 Линейные С-функции 27
1.4 Подстановка индуктивных переменных 27
1.4.1 Подстановка точек модификации 27
1.4.2 Вычисление количества итераций цикла 28
1.4.3 Подстановка индуктивных переменных 30
1.5 Снижение стоимости 30
1.6 Другие реализации алгоритмов 33
1.6.1 Идентификация индуктивных переменных 34
1.6.2 Снижение стоимости индуктивных выражений 34
1.6.3 Подстановка индуктивных переменных 35
1.7 Результаты 36
-1-
1.8 Выводы 38
2 Нормализация структуры управляющей переменной цикла 40
2.1 Использование беззнакового типа 44
2.2 Использование оператора != в условии цикла 46
2.3 Использование оператора постинкремента 49
2.4 Использование глобальной переменной в качестве верхней границы . 52
2.5 Порядок нормализации циклов 55
2.6 Ограничения применения специализации кода 57
2.7 Результаты 58
2.8 Выводы 61
3 Профилирование значений выражений для специализации кода 63
3.1 Специализация кода по конкретным значениям инвариантов 65
3.2 Профилирование значений выражений 68
3.2.1 Инструментирование программы 68
3.2.2 Использование результатов инструментирования 72
3.3 Результаты 73
3.4 Выводы 76
Заключение 78 Приложение. Внутренняя структура компилятора фирмы Sun 80 Список литературы 83 Список примеров 89 Список иллюстраций 91 Список таблиц 91
-2-
Актуальность темы. С момента появления вычислительной техники и по сегодняшний день скорость выполнения программ была и остается важной темой исследований. Один из наиболее эффективных методов увеличения скорости работы программ — использование оптимизирующих компиляторов. Увеличение мощности современных компьютеров приводит не только к ускорению выполнения программ, но и к появлению новых возможностей, в том числе и для оптимизирующих компиляторов. Кроме того, изменение архитектуры процессоров приводит к необходимости создания новых и переработки уже имеющихся методов автоматической оптимизации.
На форуме Intel для разработчиков (Intel Developer Forum, IDF), прошедшем 2-го октября 2002-го года в Москве, были названы девять основных факторов повышения производительности при использовании компиляторов Intel [11]. Среди них:
1. программная конвейеризация (software pipelining) для архитектуры Itanium,
2. автопараллелизация (autoparallelization) и
3. оптимизация по профилированию (profile guided optimization, PGO).
Программная конвейеризация — это такая трансформация циклов, которая позволяет наиболее эффективно использовать параллелизм уровня команд в большинстве современных микропроцессоров, в том числе, например, в Sun ULTRASparc™ IIICu или Intel Itanium™.
Автопараллелизация — это семейство оптимизирующих трансформаций, позволяющих запускать последовательные независимые участки программы параллель¬но в нескольких потоках управления (threads). Наиболее распространенное применение автопараллелизации — автоматическая параллелизация циклов. Автопараллелизация позволяет эффективно использовать преимущества мультипроцессорных архитектур, в том числе и псевдомультипроцессорных (например, системы HyperThreading фирмы Intel).
-3-
Оптимизация по профилированию — это многофазная схема оптимизации про¬грамм, состоящая из инструментирования программы, пробного прогона на характерном наборе данных и последующего использования полученной статистики при финальной компиляции. Оптимизация по профилированию позволяет правильно предсказывать переходы, находить критические пути исполнения, оценивать число итераций циклов и выявлять те участки программы, к которым следует применять наиболее агрессивные оптимизации.
Наиболее важные виды оптимизации не случайно связаны именно с оптимизацией циклов. Как отмечается во многих работах по оптимизирующим компиляторам, основное время исполнения большинства программ приходится именно на циклы ([20], [13, §10.2]), и поэтому оптимизации циклов уделяется наибольшее внимание при разработке компиляторов.
Основы оптимизирующего компилятора фирмы Sun для платформы SPARC закладывались в начале восьмидесятых годов прошлого века с использованием самых современных (на тот момент) технологий, а один из создателей этого компилятора, Steven Muchnick, позднее написал книгу [41], которая по праву считается одной из фундаментальных работ по компиляторам. Практически с самого начала существования данного компилятора в нем были реализованы многие классические трансформации циклов, такие, например, как вынос инвариантов цикла и снижение стоимости индуктивных выражений. С момента своего создания и по сегодняшний день компилятор фирмы Sun активно развивается — за последние годы в нем появились такие важные трансформации, как программная конвейеризация и автоматическая параллелизация, а также многие другие.
Однако, с развитием компилятора становилось очевидно, что алгоритмы, заложенные при его создании, уже перестали удовлетворять все возрастающие потребности. Среди прочего, возникла необходимость в разработке нового алгоритма снижения стоимости индуктивных выражений (далее для краткости: снижение стоимости). Вряд ли можно найти оптимизацию, изученную подробнее, чем снижение стоимости: она описана во многих книгах по компиляторам ([13, §10.2], [41, §14.1.2],
-4-
[17, §6.2.3]) и, без сомнения, так или иначе реализована во всех промышленных оптимизирующих компиляторах.
Тем не менее, новый алгоритм снижения стоимости, разработанный в рамках данной диссертационной работы, интересен как минимум по двум причинам.
Во-первых, этот алгоритм разработан не только как теоретическое построение, но и внедрен в работающий компилятор с его заданной структурой представления программы, при этом за то же время выполняет существенно большее число трансформаций, чем предыдущий алгоритм, реализованный в компиляторе Sun.
Во-вторых, в основу данного алгоритма снижения стоимости положен такой механизм символьного анализа индуктивных переменных и индуктивных выражений, который применим для очень широкого класса оптимизаций и точного аналога которому автор не нашел в известной ему литературе.
После успешного внедрения в компилятор механизма символьного анализа индуктивных выражений было решено применить данный механизм для реализации еще одной оптимизирующей трансформации — подстановки индуктивных переменных. Данная оптимизация, необходимая в первую очередь для параллелизации циклов, достаточно изучена, однако ее прежняя реализация не позволяла охватить ряд важных случаев. Применение символьного анализа к индуктивным переменным позволило существенно расширить множество обрабатываемых случаев, сохранив прежнее время компиляции.
В процессе работы над алгоритмами трансформации индуктивных переменных и в ходе исследования результатов их работы было обнаружено большое количество таких циклов, которые нельзя было трансформировать из-за неправильной структуры управляющей переменной цикла. Зачастую неправильная структура управляющей переменной цикла являлась следствием применения некоторых конструкций языка Си (и Си+—+), например, использования глобальной переменной в качестве верхней границы цикла или оператора неравенства для проверки условия выхода из цикла. Вероятно, подобные проблемы хорошо известны многим разработчикам компиляторов, однако они очень мало освещены в литературе и не были практически решены в компиляторе Sun.
В диссертационной работе предлагается метод нормализации структуры цикла с использованием специализации кода, то есть при помощи дублирования цикла и вставки в код динамической проверки определенных условий. Реализация данного метода широко использует механизм символьного анализа индуктивных переменных, упомянутый выше.
Еще одно применение специализации кода основано на использовании так называемого профиля значений, т. е. статистической информации, полученной в результате пробного запуска программы и позволяющей предсказать наиболее вероятные значения тех или иных переменных и выражений. Так, имея подробную информацию о возможных значениях некоторого инварианта цикла, можно произвести специализацию кода и подставить значение данного инварианта в одну из копий цикла. Во многих промышленных компиляторах реализованы методы использования различной профильной информации (самыми распространенными типами такой информации следует назвать профиль переходов и профиль вызовов виртуальных функций). Однако профили значений выражений не нашли пока применения в большинстве компиляторов в силу крайне низкой скорости сбора статистики о значениях выражений. В большинстве работ по профилированию выражений упоминается замедление работы профилируемых программ на два порядка и более. В рамках диссертационой работы был разработан и реализован метод профилирования значений, замедляющий профилируемые программы всего лишь на несколько процентов, вместо десятков раз. Данный “быстрый” метод позволяет собирать статистику несколько иного рода, чем ранее известные “медленные” методы. Это дает возможность не только собрать большую часть информации о значениях выражений, доступной при использовании других методов, но также получить информацию о взаимозависимости значений различных выражений.
Актуальность диссертационой работы обусловлена тем, что все исследованные методы оптимизации позволяют существенно повысить скорость выполнения про¬грамм.
-6-
Целью диссертационной работы является разработка новых и модификация имеющихся методов и алгоритмов оптимизации программ, связанных с программ¬ной конвейеризацией и автопараллелизацией, а также использующих профилирование. Исходя из поставленной цели, в диссертационной работе решаются следующие задачи:
• разработка нового алгоритма снижения стоимости для индуктивных переменных, позволяющего в ряде случаев улучшить возможности последующей программной конвейеризации;
• разработка нового алгоритма подстановки индуктивных переменных, увеличивающего возможности автопараллелизации;
• анализ и частичное решение проблем, связанных с “нестандартными” управляющими переменными циклов в языках С и C+—Н;
• создание методов профилирования значений для последующей специализации кода.
Предмет исследования составляют различные аспекты разработки и реализации алгоритмов оптимизации программ:
• разработка эффективных алгоритмов идентификации, анализа и трансформации индуктивных переменных;
• разработка эффективных методов профилирования значений и выбора участков кода для специализации;
• оценка конечной производительности оптимизированного кода.
Методы исследования заимствованы из областей системного программирования, технологии компиляции, символьной алгебры и теории графов. Эффективность разработанных алгоритмов и конечная производительность программ оценивались путем замера времени исполнения ряда тестовых программ, в первую очередь SPEC CPU2000, на двухпроцессорной рабочей станции SunBlade™ 1000.
-7-
Тестовый набор SPEC CPU2000 ([56]) — это международно признанный пакет тестов для оценки производительности вычислительных систем, состоящий из двух частей: набор программ, использующих преимущественно целочисленную арифметику (SPECint2000) и набор программ, использующих в основном арифметику с плавающей запятой (SPECfp2000). Пакет содержит в общей сложности 26 про¬грамм (12 в SPECint2000 и 14 в SPECfp2000), представляющих различные сферы применения языков программирования Си, СиН—Н, Фортран 77 и Фортран 90, таких как: архивация данных, компьютерная графика и распознавание образов, компиляция и интерпретация языков программирования, теория чисел, базы данных, искусственный интеллект (игра в шахматы), физика, химия, метеорология и др. Для каждой программы из тестового пакета имеется три набора входных данных: test — малый набор данных, используемый для проверки работоспособности теста, train — набор данных среднего размера, используемый для пробного запуска при многофазной схеме компиляции и ref — большой набор данных, используемый для измерения времени работы программы. Кроме пакета SPEC CPU2000, в процессе анализа и тестирования разработанных алгоритмов использовались тесты SPEC CPU95, bench++ и другие.
1. Разработаны новые алгоритмы идентификации и символьного анализа индуктивных переменных и выражений, а также управляющей переменной. На основе данных алгоритмов разработаны алгоритмы оптимизации: подстановка индуктивных переменных и снижение стоимости индуктивных выражений.
Новые алгоритмы позволяют:
• обрабатывать индуктивные переменные с несколькими присваиваниями;
• учитывать взаимосвязь между различными индуктивными переменными;
• анализировать и оптимизировать операторы преобразования типов, примененные к индуктивным переменным и выражениям;
• трансформировать операторы деления индуктивного выражения на константу.
2. Проведен детальный анализ проблем, возникающих в программах на языках Си и Си+—+, и связанных с нестандартными способами описания управляю¬щей переменной. Предложен механизм решения этих проблем с применением специализации кода. Рассмотрены следующие случаи и их комбинации:
• использование управляющей переменной, имеющей беззнаковый целый тип;
• использование оператора != вместо оператора < в условии завершения цикла;
• использование оператора постинкремента в условии завершения цикла;
• использование глобальной переменной (или оператора считывания из памяти) в качестве верхней границы цикла.
3. Разработан метод быстрого профилирования конкретных значений выражений, учитывающий взаимозависимость значений нескольких различных выражений. На основе этого метода разработан механизм специализации кода по профилю значений.
4. Показано, что исследованные методы оптимизации, использующие специализацию циклов, являются “агрессивными”, т. е. в некоторых случаях могут ухудшить производительность. Однако, проведенные эксперименты доказали, что использование адекватных тренировочных данных при многофазной схеме компиляции обеспечивает отсутствие отрицательного результата.
5. Все исследованные методы анализа и оптимизации циклов реализованы в оптимизирующем компиляторе для платформы SPARC, что является важным практическим результатом работы.
6. Все предложенные методы оптимизации являются универсальными, т. е. не привязаны к конкретной архитектуре, конкретному компилятору или набору тестовых задач.
7. Реализованные оптимизации позволяют существенно повысить производительность реальных программ. На программах тестового набора SPEC CPU2000 был получен прирост производительности до 12%.
Разработка и исследование в области высокоуровневых оптимизаций циклов осуществлялась (и продолжает осуществляться) в рамках проекта оптимизатора промежуточного представления iropt (см. приложение), проводимого совместно фирмами ЗАО “МЦСТ” и Sun Microsystems с 1992 года. Автором были разработаны и реализованы все оптимизации, предложенные в главах 1, 2 и 3.
В заключение автору хотелось бы поблагодарить всех специалистов, принимавших (и принимающих) участие в проекте iropt, в том числе: С. Гурьева, Е. Черниса, В. Яковлева, В. Броля (Россия) и X. Kong, Б. Синдеева (США). Я выражаю глубо¬кую признательность руководителю проекта iropt г-ну J.-Z. Wang за проявленное понимание и предоставленную возможность работать над диссертацией. Особо хочу поблагодарить моего научного руководителя к.т.н. В.Ю. Волконского и проф. В.В. Шилова, без которых данная работа не могла бы осуществиться.
[1] И. Л. Дьячков, К. С. Серебряный. Профилирование значений выражений для оптимизации программ // XXIX Гагаринские чтения. Международная моло¬дежная научная конференция. Тезисы докладов Т. 5, 2003. С. 20-21.
[2] К. С. Серебряный. Методы оптимизации программ, использующие дублирова¬ние кода // Новые материалы и технологии. Тезисы докладов Всероссийской научно-технической конференции, Т. 3, 2002. С. 40-41.
[3] К. С. Серебряный. Трансформации циклов, производимые оптимизирующими компиляторами // Современные проблемы фундаментальных и прикладных наук. Научная конференция МФТИ. Часть I: Радиотехника и кибернетика. Москва-Долгопрудный, 2002. С. 42-43.
[4] К. С. Серебряный. Способ оптимизации программ с использованием раскрутки циклов // Информационные технологии 2003, N 1. С. 12-15.
[5] К. С. Серебряный. Трансформации циклов, содержащих индуктивные пере¬менные // Информационные технологии 2003, N 9. С. 22-29.
[6] К. С. Серебряный. Нормализация структуры циклов // XXX Гагаринские чте¬ния. Международная молодежная научная конференция. Тезисы докладов Т.
5, 2004. С. 56.
[7] А. И. Голуб. С и С++. Правила программирования // М.: Восточная Книжная Компания, 1996.
[8] В. Н. Касьянов, В. А. Евстигнеев. Графы в программировании: обработка, визуализация и применение // СПб.: БХВ-Петербург, 2003.
[9] Д. Э. Кнут. Искусство программирования, 3-е изд. // М.: Вильямс, 2000.
[10] Т. Кормен, Ч. Лейзерсон, Р. Ривест. Алгоритмы: построение и анализ // М.: МЦНМО, 1999.
-83-
[11] Д. Прохоров, А. Исаев. Использование компиляторов Intel и программных средств набора Intel Threading Toolkit для создания, оптимизации и отладки одно- и многопотоковых приложений / / Материалы форума Intel для разра¬ботчиков, октябрь 2002 (CD-ROM).
[12] Б. Страуструп. Язык программирования С++. 3-е изд. // М.: БИНОМ, 1999.
[13] Д. Д Ульман, А. В. Ахо, Р. Сети. Компиляторы: принципы, технологии и инструменты //М.: Вильямс, 2001.
[14] Фортран 90. Международный стандарт //М.: Финансы и статистика, 1998.
[15] С. П. Харбисон, Г. Л. Стил. Язык программирования С //М.: Бином-Пресс, 2004.
[16] G. Aigner, U. Holzle. Eliminating virtual function calls in C++ programs // Lecture Notes in Computer Science, 1098, 1996.
[17] D. F. Bacon, S. L. Graham, O. J. Sharp. Compiler transformations for high- performance computing // ACM Computing Surveys, 26(4), pp. 345-420, 1994.
[18] T. Ball, J. R. Larus. Optimally profiling and tracing programs // ACM Transactions on Programming Languages and Systems, 16(4), pp. 1319-1360, July 1994.
[19] T. Ball, J. R. Larus. Efficient path profiling //In International Symposium on Microarchitecture, pp. 46-57, 1996.
[20] U. Banerjee. Dependence Analysis. Loop Transformations for Restructuring Compilers // Kluwer Academic Publishers, Boston, MA., 1997.
[21] D. Bernstein, D. Cohen, D. E. Maydan. Dynamic memory disambiguation for array references // Proceedings of the 27th annual international symposium on Microarchitecture, pp. 105-111, 1994.
[22] W. Blume, R. Eigenmann. Symbolic range propagation //In Proceedings of the 9th International Parallel Processing Symposium, pp. 357-363, Santa Barbara, CA, April 1995.
-84-
[23] W. Blume. Symbolic Analysis Techniques for Effective Automatic Parallelization // PhD thesis, Dept. of Computer Science, University of Illinois at Urbana- Champaign, June 1995.
[24] M. Burrows, U. Erlingson, S.-T. Leung, M. T. Vandevoorde, C. A. Waldspurger, K. Walker, W. E. Weihl. Efficient and flexible value sampling //In Architectural Support for Programming Languages and Operating Systems, pp. 160-167, 2000.
[25] B. Calder, P. Feller, A. Eustace. Value profiling and optimization // Journal of Instruction Level Parallelism, 1999.
[26] B. Calder, P. Feller, A. Eustace. Value profiling //In International Symposium on Microarchitecture, pp. 259-269, 1997.
[27] B. Calder, D. Grunwald. Reducing indirect function call overhead in C++ programs //In Conference Record of POPL ’94: 21st ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, pp. 397-408, Portland, Oregon, 1994.
[28] J. W. Davidson, S. Jinturkar. Improving instruction-level parallelism by loop unrolling and dynamic memory disambiguation // Proceedings of the 28th annual international symposium on Microarchitecture, pp. 125-132, 1995.
[29] R. van Engelen. Symbolic evaluation of chains of recurrences for loop optimization // Technical report, TR-000102, Computer Science Deptartment, Florida State University, 2000.
[30] P. Feller. Value profiling for instructions and memory locations // Technical repor CS98581, Department of Computer Science and Engineering, University of California, San Diego, Apr. 1998.
[31] F. Gabbay, A. Mendelson. Can program profiling support value prediction?
//In International Symposium on Microarchitecture, pp. 270-280, 1997.
[32] D. M. Gallagher, W. Y. Chen, S. A. Mahlke, J. C. Gyllenhaal, W. W. Hwu. Dynamic memory disambiguation using the memory conflict buffer // Proceedings of the
-85-
sixth international conference on Architectural support for programm ing languages and operating systems, pp. 183-193, 1994.
[33] M. P. Gerlek, E. Stoltz, M. Wolfe. Beyond induction variables: Detecting and classifying sequences using a demand-driven SSA form // ACM Transactions on Programming Languages and Systems, 17(1), pp. 85-122, January 1995.
[34] D. Ginsburg, B. Groose, J. Taylor, B. Vernescu. The History of the Calculus and the Development of Computer Algebra Systems
// http://www.math.wpi.edu/IQP/BVCalcHist
[35] M. R. Haghighat, C. D. Polychronopoulos. Symbolic Program Analysis and Optimization for Parallelizing Compilers //In Conference Record of the 5th Workshop on Languages and Compilers for Parallel Computing, Yale University, Department of Computer Science, 1992.
[36] M. R. Haghighat, C. D. Polychronopoulos. Symbolic analysis for parallelizing compilers // ACM Transactions on Programming Languages and Systems, 18(4), pp. 477-518, July 1996.
[37] S. P. Harbison, G. L. Steel, Jr. C, a reference manual // 1990. Third edition. Prentice-Hall, 1991.
[38] W. Harrison. Compiler Analysis of the Value Ranges for Variables // IEEE Trans. on Software Engineering, vol. SE-3, no. 3, pp. 243-250, May 1977.
[39] A. S. Huang, G. Slavenburg, J. P. Shen. Speculative disambiguation: a compilation technique for dynamic memory disambiguation // Proceedings of the 21ST annual international symposium on Computer architecture, pp. 200-210, 1994.
[40] C.-K. Luk. Memory disambiguation for general-purpose applications // Proceedings of the 1995 conference of the Centre for Advanced Studies on Collaborative research, p 43, 1995.
-86-
[41] S. S. Muchnick. Advanced compiler design and implementation // Morgan Kaufmann Publishers Inc., 1997.
[42] R. Muth. Alto: A platform for object code modification // PhD thesis, Department of Computer Science, University of Arizona, 1999.
[43] R. Muth, S. A. Watterson, S. K. Debray. Code specialization based on value profiles //In Static Analysis Symposium, pp. 340-359, 2000.
[44] D. A. Padua, M. J. Wolfe. Advanced compiler optimizations for supercomputers // Commun. ACM, vol. 29, no. 12, pp. 1184-1201, 1986.
[45] J.R.C. Patterson. Accurate static branch prediction by value range propagation // In Proceedings of the ACM SIGPLAN ’95 Conference on Programming Language Design and Implementation, pp. 67-78, 1995.
[46] E. Salami, J. Corbal, C. Alvarez, M. Valero. Cost effective memory disambiguation for multimedia codes // Proceedings of the international conference on Compilers, architecture, and synthesis f or embedded systems, pp. 117-126, 2002.
[47] Y. Sazeides, J. E. Smith. The predictability of data values
//In International Symposium on Microarchitecture, pp. 248-258, 1997.
[48] J. Sheldon, W. Lee, B. Greenwald, S. Amarasinghe. Strength reduction of integer division and modulo operations // citeseer.nj.nec.com/503048.html
[49] S. Watterson, S. Debray. Goal-directed value profiling // Lecture Notes in Computer Science, 2027, 2001.
[50] S. Wolfram. The Mathematica Book, 4th ed.
// Wolfram Media/Cambridge University Press, 1999.
[51] http://docs.sun.com
[52] http://java.sun.com
[53] http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC
-87-