69952.fb2
Он обнаружил, что его коллективы программистов не укладывались в график почти наполовину - каждая задача занимала в два раза больше времени, чем ей отводилось по плану, несмотря на то, что оценки были очень тщательны (их делали опытные люди, которые определили затраты в человеко-часах для нескольких сотен подзадач с помощью схем PERT). Когда выявилось отставание от графика, Портман попросил своих сотрудников вести подробные ежедневные записи расхода времени. Эти записи показали, что ошибочная оценка полностью объясняется тем фактом, что коллективы тратили только 50% рабочего времени собственно на программирование и отладку. Остальное врем"я уходило на побочные, но срочные дела, совещания, За работу с бумагами, общественные дела, болезни, личные нужды, а также терялось из-за простоев машины. Короче говоря, при составлении графика было сделано нереальное предположение о том, какая часть времени затрачивается непосредственно на работу. Мой собственный опыт полностью подтверждает это заключение.
Данные Арона
Джоель Арон, руководитель отдела системной технологии фирмы IBM в Гейтесбурге (штат Мэриленд), изучал производительность программистов, принимавших участие в разработке девяти больших систем (большой считалась система объемом более 30 тыс. команд, в создании которой участвовало более 25 программистов)7). Он классифицировал системы по числу сопряжении между программистами (и тем самым, по числу отдельных частей системы) и получил следующие значения производительности одного программиста:
Очень мало сопряжения 10000 команд в год
Среднее число сопряжения 5000 " "
Много сопряжении 1500 " "
Но в этих данных учитывается только время на проектирование и написание программ. Если же разделить их на коэффициент два, покрывая тем самым затраты на системную отладку, то эти данные окажутся вполне сопоставимыми с данными Харра.
Данные Харра
Джон Харр, руководитель работ по программированию системы электронной коммутации фирмы Bell Telephone Laboratories обобщил свой опыт в докладе^ представленном в 1969 г. на осенней объединенной конференции по вычислительной технике8). Эти данные приведены в табл. 8.1 и на рис. 8.2 и 8.3.
Таблица 8.1
Табл. 8.1 является очень поучительной. Первые две задачи - это управляющие программы; две последние - трансляторы. Производительность определяется как число команд, отлаженных за человеко-год. Сюда включается написание программ, отладка компонент и системная отладка. Неясно, насколько здесь учитывались затраты на проектирование, а также на обслуживание машины, документирование и т. д.
Производительность разбивается на две категории:
для управляющих программ она составляет около 600 команд на человеко-год,
а для трансляторов - около 2200 команд на человеко-год.
Отметим, что все четыре программы примерно одного размера - различия в величине рабочих групп, в сроках и в чпсле модулей. Что здесь причина и что следствие? Потому ли создание управляющих программ требует больше людей, что они сложнее? Или же требуется больше модулей и больше человеко-месяцев именно потому, что заранее было больше занято людей? Потому ли требуется больше времени, что задача более сложная, или это происходит из-за большего числа занятых в ней людей? Определенный ответ дать достаточно трудно. Управляющие программы действительно более сложны. Однако если не принимать во внимание такие неопределенности, то вышеприведенные цифры описывают реальную производительность, достигнутую в большой системе с использованием современных методов программирования. И в этом аспекте они имеют достаточно важное значение.
Рис. 8.2. Предсказываемая и реальная скорости программирования системы электронной коммутации.
Рис. 8.3. Предсказываемая и реальная скорости отладки системы электронной коммутации.
На рис. 8.2 и 8.3 приводятся некоторые интересные данные о скорости программирования и отладки по сравнению с предсказаниями.
Данные по OS/360
Опыт разработки OS/360, не учитывавший данных Харра, тем не менее подтверждает их. Производительность групп, занимавшихся управляющими программами, составила 600 - 800 отлаженных команд на человеко-год. Производительности в 2000 - 3000 отлаженных команд на человеко-год достигли группы, разрабатывавшие языковые трансляторы. Сюда входит проектирование на уровне групп, написание программ отладка компонент, комплексная отладка и некоторые вспомогательные операции. Насколько я могу судить, ати данные вполне сопоставимы с данными Харра.
Данные Арона, Харра и OS/360 подтверждают существенные различия в производительности программистов в зависимости от сложности и трудности самой задачи. Чтобы не увязнуть в трясине определения этой сложности, я предлагаю придерживаться следующего правила: трансляторы в три раза сложнее обычных прикладных программ, а операционные системы в три раза сложнее трансляторов9).
Данные Корбато
Данные Харра и фирмы IBM относятся к программированию на языке ассемблера. Данные о производительности программирования на языках высокого уровня, кажется, еще не публиковались. Корбато из проекта MAC Массачусетского технологического института сообщает среднюю производительность в 1200 отлаженных операторов на PL/I для системы Multics (объемом один, два миллиона команд)10). :
Эта цифра очень показательна. Так же как и другие проекты, Multics содержит управляющие программы и трансляторы. Как и другие, он производит комплексный программный продукт, отлаженный и снабженный документацией. Поэтому данные должны быть сравнимы по затраченным усилиям. И действительно, эта производительность представляет собой хорошую среднюю величину между производительностью разработчиков управляющей программы и тех, кто писал трансляторы в других проектах.
Но цифры Корбато говорят об операторах на человеко-год, а не о командах! Каждый оператор в его системе соответствует приблизительно трем-пяти словам ручной программы. Отсюда два важных вывода:
* производительность представляется константой на уровне элементарных операторов, т. е. по отношению к затратам на осмысление операторов и к ошибкам, которые они могут содержать '');
* производительность программирования можно увеличить по крайней мере в пять раз путем использования подходящего языка высокого уровня12).
IX. ДЕСЯТЬ ФУНТОВ В ПЯТИФУНТОВОМ МЕШКЕ
"Автор должен брать пример с Ноя и научиться, как он это делал на своем ковчеге, помещать так много всего в таком малом объеме.
(Сидней Смит "Эдинбургское обозрение")
Размер программы как стоимость
Какова стоимость программы? Если не рассматривать время выполнения программы, то именно ее объем является основным показателем ее стоимости в глазах пользователя. Это справедливо даже для арендуемых программ, где пользователь платит автору сумму, составляющую, по сути, часть стоимости разработки. Рассмотрим диалоговую систему математического обеспечения APL, разработанную фирмой IBM. Она сдается в аренду за 400 долларов в месяц и требует для своего использования по крайней мере 160 тыс. байтов памяти. В модели ЩМ 370/165 стоимость аренды памяти составляет 12 долларов за тысячу байтов в месяц. Если программа работает круглосуточно, то стоимость ее использования составит 400 долларов за математическое обеспечение и 1920 долларов за память. Если система APL используется только 4 часа в день, то стоимость составит 400 долларов арендной платы ва математическое обеспечение и 320 долларов за память в месяц.
Нередко приходится слышать, с каким ужасом воспринимается тот факт, что в машине с памятью 2 млн. байтов операционная' система может занимать 400 тыс. байтов. Ужасаться так же глупо, как критиковать Боинг 747 за то, что он стоит 27 миллионов долларов. Необходимо только задать себе вопрос: а что операционная система делает? Что можно получить аа свои деньги в смысле удобства и производительности (при эффективном использовании системы)? Может быть, 4800 долларов в месяц, затрачиваемые на аренду памяти, более целесообразно истратить на другое оборудование, на программистов, на прикладные программы?
Разработчик системы превращает часть отведенных ему ресурсов оборудования в память с резидентными программами, когда он уверен, что для пользователя это лучше, чем иметь дело с сумматорами, дисками и т. д. Поступать иначе было бы в высшей степени безответственно, и результат должен оцениваться как одно целое. Нельзя критиковать систему программирования за размер как таковой, и в то же время постоянно выступать за все более тесное объединение проектов создания аппаратуры и математического обеспечения.
Поскольку львиная доля затрат пользователя отводится на программу, разработчик комплексного программного продукта должен установить контрольные цифры, следить за их соблюдением и придумывать методы уменьшения размеров программ точно так же, как разработчик аппаратуры устанавливает контрольные значения числа компонент, следит за их соблюдением и изобретает методы их сокращения.
Контроль за размерами программ
Управление размерами программ представляет для руководителя проекта частично техническую, а частично - административную задачу. Для установления размеров предлагаемых систем необходимо изучить потребности пользователей и те прикладные области, в которых они работают. Далее эти системы следует разбить на части и определить контрольные цифры размеров каждой компоненты. Поскольку с изменением размеров программы быстродействие меняется очень резко, установление контрольных цифр требует от руководителя профессиональной ловкости и знания допустимых соотношений в каждой части системы. Кроме того, мудрый руководитель всегда оставляет для себя лазейку, которой он сможет воспользоваться впоследствии. Хотя в OS/360 все это было проделано очень тщательно, не обошлось без болезненных уроков. Во-первых, недостаточно просто установить контрольные цифры размеров оперативной памяти, необходимо учесть все аспекты, связанные с размером программы. Большая часть предыдущих операционных систем размещалась на лентах и поскольку поиск на лентах занимал много времени, это препятствовало их интенсивному вызову из сегментов программы. Система OS/360, как и ее непосредственные предшественники - операционные системы Stretch и DOS IBM 1410/7010, располагалась на дисках. Ее создатели наслаждались свободой дешевого обращения к дискам. Первоначальный результат был катастрофичным для производительности.
При установлении размеров оперативной памяти для каждой компоненты бюджет расхода памяти не устанавливался заранее. Как и предсказывали сверхпроницательные люди, программист, обнаруживая, что его программа выходит за отведенный ему участок оперативной памяти, разбивал ее на сегменты. Тем самым увеличивались общие размеры системы и уменьшалась скорость выполнения. Наша служба административного контроля не выявляла таких случаев. Каждый сообщал, какой объем оперативной памяти он использует, и если программист оставался в пределах контрольных цифр, то никто не беспокоился. К счастью, пришел день, когда начала работать программа, моделирующая производительность OS/360. Первые же результаты показали, что не все благополучно. Фортран Н на машине IBM 360/65 с барабанами транслировался со скоростью пять операторов в минуту. Расследование показало, что модули управляющей программы осуществляли слишком много обращений к дискам. Даже очень часто используемые модули супервизора "ходили к колодцу с наперстками" п результат весьма напоминал непрерывную "лихорадку" памяти.
Первая мораль ясна: устанавливайте не только размеры резидентных частей, но и общие размеры памяти, а также вводите ограничения на число обращений к внешней памяти.
Второй урок был очень похожим. Бюджеты памяти были установлены прежде, чем было сделано точное распределение функций в каждом модуле. В результате, как только программист начинал испытывать нехватку памяти, он смотрел, нельзя ли "перелезть через забор" в память соседа. Таким образом, буферы, отведенные управляющей программе, становились частью памяти пользователя. И что еще серьезнее, такая же ситуация сложилась со всеми видами управляющих блоков, и в результате ставились под угрозу защита памяти и надежность всей системы.
Вторая мораль тоже ясна: точно определяйте функции модуля при установлении его размеров.
И третий, гораздо более глубокий, урок можно извлечь из этого опыта. Проект был достаточно велик, а административная связь достаточно плоха, так что многие члены коллектива вели себя как соперники, ломающие копья, а не как строители, совместно создающие программный продукт. Каждый старался оптимизировать свой кусок программы с тем, чтобы уложиться в контрольные цифры; однако мало кто заботился о том, во что все это выльется для заказчика. Такое нарушение ориентации и связи представляет главную опасность для больших проектов.
В течение всей реализации системные архитекторы не должны терять бдительности, чтобы сохранить концептуальное единство проекта. Кроме этих механизмов принуждения существенную роль должно сыграть и отношение самих разработчиков. Может быть, самая важная функция руководителя программистского проекта заключается в воспитании у программистов внимания к нуждам пользователя и к интересам всей системы.
Методы экономии памяти
Никакие меры по установлению бюджета расхода памяти и по контролю за его соблюдением не помогут уменьшить размера программы. Здесь нужны изобретательность и мастерство.
Очевидно, что чем больше функций, тем больший объем памяти требуется при постоянном быстродействии. Прежде всего мастерство необходимо при установлении возможных компромиссов между функциями и размерами программы. Но это вопрос очень тонкой политики. В какой мере право выбора может быть предоставлено пользователю? Можно написать программу со многими факультативными свойствами, каждое из которых требует совсем немного памяти. Можно придумать генератор, который будет располагать списком вариантов и приспосабливать программу к каждому из них. Но для каждого конкретного набора вариантов более монолитная программа требует меньшего объема памяти. Здесь как в автомобиле: лампа, зажигалка и часы, встроенные в один блок, будут стоить дешевле, чем их отдельное исполнение. Поэтому сам разработчик должен определять степень дробления вариантов, выбираемых пользователем.
При разработке системы с широким диапазоном размеров памяти возникает другой важнейший вопрос. Существуют эффекты, ограничивающие область допустимых размеров памяти даже при очень мелком дроблении функции. Действительно, в самых малых системах большинство модулей будет в памяти перекрываться. Значительная часть резидентной памяти в таких системах должна быть выделена как буфер-пая или страничная область, в которую попадают другие части системы. Ее величина определяет размеры всех модулей. Кроме того, распределение функций системы по мелким модулям приводит к потере и производительности, и памяти. В, большой системе, где буферная область может быть в двадцать раз больше, сокращается лишь число обращений к памяти, однако остаются затруднения с быстродействием и памятью из-за малых размеров модулей. Этот эффект ограничивает максимальную эффективность системы с малыми модулями.
Другая область, требующая мастерства,- это достижение компромисса между быстродействием системы и объемом памяти. Для данной функции чем больше объем памяти, тем быстрее система. Это справедливо для поразительно широкого круга случаев. Именно этот факт делает разумным установление бюджета расхода памяти.
Руководитель, если он хочет помочь своей группе добиться хорошего соотношения между быстродействием и памятью, должен поступить следующим образом.