Научная статья на тему 'Программисты, компиляторы, процессоры - поиск единого вектора'

Программисты, компиляторы, процессоры - поиск единого вектора Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
188
48
i Надоели баннеры? Вы всегда можете отключить рекламу.

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Боб Евгений Борисович, Латников Андрей Викторович, Мальцев Александр Михайлович, Потехин Андрей Евгеньевич

В статье приводится анализ недостатков современных подходов к программированию с точки зрения повышения производительности. Предлагается использование технологии автоматного программирования с поддержкой этой технологии на уровне «железа».

i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Текст научной работы на тему «Программисты, компиляторы, процессоры - поиск единого вектора»

ПРОГРАММИСТЫ, КОМПИЛЯТОРЫ, ПРОЦЕССОРЫ - ПОИСК

ЕДИНОГО ВЕКТОРА Е.Б. Боб, А.В. Латников, А.М. Мальцев, А.Е. Потехин Научный руководитель - д.т.н., профессор А.А. Шалыто

В статье приводится анализ недостатков современных подходов к программированию с точки зрения повышения производительности. Предлагается использование технологии автоматного программирования с поддержкой этой технологии на уровне «железа».

Введение

В данной статье рассматриваются современные подходы к программированию и созданию микропроцессоров. Порочная практика создания программного обеспечения привела к тому, что ресурсы производительности микропроцессоров каждого нового поколения сводятся на нет уже к моменту их появления. Каким бы быстрым не было «железо», программисты всегда находят способы растратить новые мощности практически впустую, за редким исключением узкоспециализированных программ (обработка видео, аудио и т.п.). Ситуация усугубляется с появлением многоядерных систем. Авторами предлагается использовать технологию автоматного программирования [1] с поддержкой автоматов на уровне «железа», что позволит повысить производительность систем и упростить распараллеливание программ.

Программное обеспечение и производительность компьютерных систем

Бурное развитие микропроцессорной техники в последнее десятилетие воспринимается обывателем как гигантский скачок в мире высоких технологий. Каждое новое поколение микропроцессоров удивляет нас своими возможностями. Не отстают и средства разработки программного обеспечения. Сегодня рядовым программистам уже необязательно знать тонкости «железа», что делает их труд более универсальным. Однако у каждой медали есть и обратная сторона. Подобное отстранение не может не сказаться на производительности программного обеспечения. На протяжении долгого времени считалось, что нововведения в микропроцессорах должны с лихвой компенсировать этот недостаток. А действительно ли современные микропроцессоры настолько уникальны?

«Мы гордимся современной аппаратурой и пренебрежительно относимся к достижениям двадцати-тридцатилетней давности, между тем это ослиная гордость. Чтобы там ни говорила реклама, невозможно не признать, что за последнее время ничего принципиально нового не придумано. Эксплуатируется сравнительно небольшое количество весьма древних идей и, если что и совершенствуется, - так это проектные нормы. То, что раньше занимало целый шкаф, теперь свободно умещается на ладони. Нет ничего такого, что в том или ином виде не присутствовало бы в «динозаврах» первых поколений» [2].

Миф о всемогущих микропроцессорах сыграл с нами злую шутку. За несколько десятилетий не было создано ничего принципиально нового, а программистов продолжали учить по-старому. Все новшества средств разработки программного обеспечения - это не что иное, как надстройки над старыми технологиями. Авторы статьи уверены, что настало время обратиться к истокам и пересмотреть свой взгляд на очень многие вещи.

Возможен ли вечный рост?

Выведенный более сорока лет назад закон Мура работает, и по сей день. Одна из его формулировок гласит, что производительность микропроцессоров удваивается ка-

ждые 18 месяцев. Фактически наблюдается экспоненциальный рост производительности микропроцессоров на протяжении почти что полувека! Возникает вопрос: а может ли такой рост продолжаться вечно? Профессор экономики Кеннет Болдинг однажды так высказался по поводу подобного положения вещей: «тот, кто верит, что экспоненциальный рост на земле может продолжаться вечно, либо сумасшедший, либо экономист» [3]. Хотя это высказывание относилось к экономическому росту, оно легко может быть применено и к росту производительности компьютерных систем. Достаточно только заменить слово «экономист» на «программист». Сегодня разработчики программного обеспечения мало задумываются о производительности как таковой, свято веря в то, что в будущем их программы будут работать быстрее за счет более производительного «железа». Производителям же микропроцессоров с каждым годом становится все труднее преодолевать технические барьеры и увеличивать рост производительности в соответствии с законом Мура. Если посмотреть на сам термин «производительность», то можно заметить, что его смысл существенно изменился за последние годы. Многие модные новшества в микропроцессорах имеют значение при обработке потоковых данных (звук, видео), но мало сказываются на обычных «поведенческих» программах. Более того, скорость работы последних, как правило, уменьшается. Только за счет повышения тактовой частоты это незаметно [4]. Дальнейшее повышение тактовой частоты становится дорогим и, следовательно, нецелесообразным с экономической точки зрения. Да и технический порог уже не за горами. Появившиеся в последнее время многоядерные архитектуры - это, по логике вещей, шаг в верном направлении. Однако и здесь все не так просто: увеличение числа ядер в N раз не увеличивает производительность во столько же раз. Более того, прирост производительности падает, а сложность системы растет при добавлении в систему каждого нового ядра, и оба эти процесса являются экспоненциальными [5]. В основном это происходит из-за необходимости организации обмена и синхронизации данных при выполнении программы. Современные средства программирования не позволяют решать подобные задачи, оставляя их на откуп производителям «железа». При этом программисты живут в своем «линейном» мире и стараются абстрагироваться от такого рода проблем. Сегодня предпринимаются попытки ввести в языки программирования специальные директивы для сближения программистов и аппаратчиков [6]. Авторы статьи уверены, что эти попытки обречены на провал - слишком уж большая пропасть образовалась между разработчиками программного обеспечения и производителями микропроцессоров. Подходы к разработке программного обеспечения не пересматривались уже несколько десятков лет, и попытки их подстройки неизбежно приведут к неудаче. Здесь требуются качественные изменения, главным из которых станет отход от программирования с использованием флагов. Иначе получается все как в известной басне И. А. Крылова «Лебедь, Рак и Щука», где в роли главных героев выступают программисты, компиляторы и микропроцессоры. А можно ли направить их усилия в одном направлении?

Программисты

Программисты - кто они такие? На первый взгляд, вопрос кажется бессмысленным - это люди, пишущие код. К большому сожалению, подавляющее большинство людей в мире информационных технологий именно так и считает. Любой человек, выучивший синтаксис какого-либо языка программирования, сегодня гордо называет себя программистом. А программист-профессионал, по мнению многих, это человек, написавший код так, что его никто, кроме него, не понимает. На самом деле, это не программисты, а кодировщики, в первом случае, и плохие кодировщики - во втором. Задача программистов - это разработка поведенческой модели. Сегодня же их усилия в основном тратятся на борьбу с неправильными указателями, утечками памяти и т.п. На-

стоящему программисту, по большому счету, абсолютно неважно, на каком языке разрабатывать программу, так как его задача - разработать алгоритм в соответствии с требованиями, руководствуясь которыми кодировщики будут «кодировать».

Существует процесс разработки программного обеспечения, который и предусматривает подобный подход: технические эксперты разрабатывают дизайн на основе технического задания, а «программисты» пишут код в соответствии с дизайном. Все абсолютно верно - дизайн соответствует требованиям, код - дизайну. Однако есть нюанс, ломающий эту идеалистическую модель - человеческий фактор. Технический эксперт, как правило, разрабатывает дизайн на «бумаге», а «программист» переносит его в код, руководствуясь своими домыслами. Причем основной целью дизайна является описание поведения системы. Даже если предположить, что дизайн полностью соответствует требованиям, нельзя утверждать, что код также будет им соответствовать. Просто потому, что «программист» - это человек, а человеку свойственно ошибаться. Исправить подобное положение вещей призвано дорогостоящее «двойное» тестирование. Термин «двойное» означает, что одновременно тестируются и дизайн, и код, что не лучшим образом сказывается на конечном качестве продукта - как на его поведении, так и на отказоустойчивости.

Компиляторы и микропроцессоры

Компиляторы облегчают жизнь разработчикам программного обеспечения, так как изолируют последних от аппаратных особенностей той или иной системы, делая программистов независимыми от «железа». В последнее время компиляторы стали достаточно «умными» - они учитывают специфические особенности микропроцессоров при оптимизации размера кода, быстродействия и т. п. Но столь ли они всемогущи? Нет - компиляторы не в состоянии исправлять такие упущения программистов, как неоптимальное использование ресурсов, неверную реализацию алгоритмов и т.п. Таким образом, можно утверждать, что разработчики компиляторов в основном ориентируются на особенности микропроцессоров. Однако и здесь все не так идеально, как хотелось бы. Ведь код, генерируемый компилятором, и код, исполняемый ядром микропроцессора - зачастую абсолютно разные сущности. Дело в том, что многие микропроцессоры транслируют коды команд программы в свое внутреннее представление.

Теперь начинается самое интересное - подходим к сердцу системы. Что знают рядовые программисты о современных микропроцессорах? Микропроцессор выполняет программный код, обращаясь к памяти и устройствам ввода/вывода. Причем память линейная, скорее всего виртуальная, и ее объем практически неограничен. И сегодня этих сведений оказывается вполне достаточно для написания программы. Это отчасти так, если создается некое приложение, которое некритично ко времени исполнения. Однако, в конце концов, рядового пользователя начинают раздражать «тормозящие» программы, которые съедают к тому же львиную долю дискового пространства. Что уж говорить о серьезных встроенных системах!

Можно было бы пожалеть бедный микропроцессор - ведь ему приходится перерабатывать столько неоптимального кода, используя столь хитроумные и сверхсложные механизмы: кэширование, предсказание переходов, переупорядочивание команд на конвейере и т. п. Однако сам микропроцессор и его окружение (чипсет, память) - это часть проблемы. Архитектура микропроцессора рассчитана на одиночное плавание -процессор не принимает никаких управляющих директив программиста, кроме непосредственно кода. И даже о том, что программисту абсолютно очевидно, микропроцессор не имеет ни малейшего представления.

Что оказывает наибольшее влияние на производительность современного микропроцессора? Количество ядер? Тактовая частота? Нет! Самое существенное влияние оказыва-

ют программные переходы и обращения к памяти, которая, несмотря на все ухищрения, работает гораздо медленнее ядра микропроцессора. Представим себе конвейерное производство - четкий и отлаженный механизм. Ни одного лишнего движения - каждая деталь доставляется со склада и подается на конвейер в то самое время, когда она необходима. Рабочие (роботы) не простаивают ни секунды - каждый хорошо проинструктирован (запрограммирован) на выполнение определенной задачи. Вдруг, ни с того, ни с сего, со склада начинают доставлять абсолютно другие детали. Рабочие не знают, что с ними делать - конвейер останавливается. То, что находилось на конвейере в этот момент, идет в утиль. Примерно то же самое происходит и в микропроцессоре. При любом программном переходе конвейер команд должен быть очищен и перезагружен новыми командами. Другая ситуация - когда закрывают один из складов, и детали к конвейеру приходится везти из соседнего города. Это похоже на обращение к новой области памяти. Если прочитать, например, пособие по оптимизации обращений к памяти для конкретного микропроцессора/чипсета и попытаться написать программу в соответствии с рекомендациями, то рядовой программист просто не сможет ее понять. Смешно, но изощренные алгоритмы, которыми забивают головы сегодняшним студентам, проигрывают по быстродействию простым реализациям, учитывающим особенности микропроцессора/чипсета. И проигрывают в разы, а всемогущие компиляторы и здесь оказываются бессильными [2].

Три кита

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

Во-первых, необходимо избавиться от таких архаизмов, как указатели, ручное выделение и освобождение памяти, переходов и т. п. Можно спросить, а как же тогда писать программы? При тех подходах, которые существуют сегодня - никак. Но в том-то и дело, что сами эти подходы требуется изменить. Предположим, что программа разбита на две части: логическую (поведенческую) и исполняемую (простейшие обработчики, из которых вынесена вся логика) [7]. «Высокоуровневые» программисты должны сосредоточиться на логической, а «низкоуровневые» - на исполняемой части. Первая часть будет фактически дизайном - его можно проверить, так как поведение системы задается требованиями. Во второй же части логика вообще отсутствует, а соответственно нет и переходов - такой код очень легко тестировать, особенно если ручное выделение и освобождение памяти запрещено, а указатели отсутствуют.

Во-вторых, функции компилятора - собрать обе части программы. Вдобавок компилятор должен проанализировать, какие ресурсы требуются тому или иному обработчику, и добавить соответствующее описание в программу. И все - никаких ухищрений (оптимизаций и т. п.).

В-третьих, аппаратная часть должна полностью управляться логической частью программы - в этом случае переходы будут известны заранее, и можно исключить эвристический предсказатель из системы. Сердцем такой системы станет «поведенческий» процессор - он будет реагировать на внешние (внутренние) воздействия и, работая в соответствие с логической частью программы, выбирать и передавать код испо-ляемых модулей (обработчиков) различным исполнительным устройствам. Причем выбор конкретного исполнительного устройства будет осуществляться в соответствии с описаниями, подготовленными компилятором. При таком подходе работа конвейера команд станет управляемой, а выборка памяти для конечных обработчиков будет делаться заранее. Фактически код программы будет формироваться на лету.

То, что было описано выше, является ничем иным, как автоматным программированием. Позвольте, скажете вы, но автоматное программирование применяется программистами уже сегодня! И да, и нет. Дело в том, что сегодня автоматы являются частью программы. Предлагаемый же подход представляет собой не программно-аппаратный комплекс, а автоматно-аппаратный комплекс, в котором автоматы являются единственным возможным методом создания программ. Автоматы должны заменить операционные системы: драйвера уйдут в прошлое - внешние устройства будут напрямую воздействовать на автоматы. Сервисы операционной системы должны быть стандартизованы и написаны на автоматах, равно как и все другие сервисы. В этом случае необходимую конфигурацию операционной системы (да и всей системы в целом) можно будет просто собирать как из кубиков. Если вдобавок к этому унифицировать исполняемый код обработчиков, то коэффициент переиспользования будет очень высоким.

Автоматное программирование дает неоспоримое преимущество при написании поведенческих программ: упрощается как понимание алгоритма, так и сопровождение программного продукта. Сегодня дизайнеры сложных систем все равно в той или иной степени используют автоматный подход при проектировании. Однако при компиляции все преимущества автоматов растворяются: микропроцессор уже не может оперировать логикой состояний для предсказания переходов. Предлагаемая концепция автоматно-аппаратного комплекса позволяет донести логику работы программы до «железа» в неизменном виде. При таком подходе эвристические механизмы не будут требоваться. Новое «железо» сможет работать в полном соответствиии с логикой программы, заранее выбирая те области памяти, которые ему необходимы.

В настоящее время авторы статьи работают над синтаксисом языка описания автоматов и прототипом автоматного компилятора, способного разделять «логическую» и «исполняемую» части программы. На первом этапе на выходе компилятора предполагается получать программный код, в котором логическая часть будет интегрирована с исполняемой. Этот код будет использоваться для проработки технологии и устранения выявленных недостатков. В дальнейшем планируется создать программные модели «логического» и «исполнительного» процессоров - прототип автоматного «железа». На этом прототипе описанная технология будет проверена в полном объеме.

Заключение

Современные микропроцессоры и средства разработки программного обеспечения в результате своего развития оказались оторванными друг от друга. Компиляторы, призванные объединить эти два полюса, справляются со своей задачей недостаточно эффективно. С появлением многоядерных архитектур эффективность существующего подхода снижается еще больше. В данной работе предпринята попытка анализа противоречий, а также способов выхода из сложившейся ситуации. Предлагается использовать концепцию автоматного программирования с поддержкой автоматов на уровне «железа». Несмотря на то, что эта концепция требует полного пересмотра процесса разработки программного обеспечения и микропроцессоров, такой подход оказывается наиболее оптимальным с точки зрения увеличения производительности и распараллеливания вычислений.

Литература

1. Шалыто А.А. Технология автоматного программирования. / Труды Всероссийской научной конференции «Методы и средства обработки информации» - М.: МГУ. 2003. - С. 528-535.

2. Касперский К. Техника оптимизации программ. Эффективное использование памяти. - СПб.: БХВ-Петербург. 2003. - 464 с.

3. Википедия [Электронный ресурс], Режим доступа: http://en.wikipedia.org/wiki/Kenneth_Boulding, свободный. - Загл. с экрана. - Яз. англ.

4. The Microarchitecture of the Pentium 4 Processor / Intel Technology Journal Q1, 2001

5. Amdahl G. Validity of the Single Processor Approach to Achieving Large-Scale Computing Capabilities. / AFIPS Conference Proceedings. - 1967. - Р. 483-485.

6. OpenMP [Электронный ресурс], Режим доступа: http://www.openmp.org/blog/, свободный. - Загл. с экрана. - Яз. англ.

7. Шалыто А.А. Логическое управление. Методы аппаратной и программной реализации. - СПб: Наука, 2000. - 784 с.

i Надоели баннеры? Вы всегда можете отключить рекламу.