Вопрос 10 Что такое язык ассемблера?
Язык ассемблера — это язык, в котором каждое высказывание соответствует ровно одной машинной команде. Иными словами, существует взаимно однозначное соответствие между машинными командами и операторами в программе на языке ассемблера. Если каждая строка в программе на языке ассемблера содержит ровно один оператор и каждое машинное слово содержит ровно одну команду, то программа на языке ассемблера в п строк произведет программу на машинном языке из п слов.
Мы используем язык ассемблера, а не программируем на машинном языке (в шестнадцатеричной системе счисления), поскольку на языке ассемблера программировать гораздо проще. Использовать символьные имена и адреса вместо двоичных и восьмеричных намного удобнее. Многие могут запомнить, что обозначениями для сложения (add), вычитания (subtract), умножения (multiply) и деления (divide) служат команды ADD, SUB, MUL и DIV, но мало кто может запомнить соответ ствующие числа, которые использует машина. Программисту на языке ассемблера нужно знать только символические названия, поскольку ассемблер транслирует их в лташннные команды.
Это утверждение касается и адресов. Программист на языке ассемблера может дать имена ячейкам памяти, и уже ассемблер должен будет выдавать правильные числа. Программист на машинном языке всегда должен работать с числовыми номерами адресов. Сейчас уже нет программистов, которые пишут программы на машинном языке, хотя несколько десятилетий назад до изобретения ассемблеров программы именно так и писались.
Язык ассемблера имеет несколько особенностей, отличающих его от языков высокого уровня. Во-первых, это взаимно однозначное соответствие между высказываниями языка ассемблера и машинными командами (об этом мы уже говорили). Во-вторых, программист на языке ассемблера имеет доступ ко всем объектам и командам, присутствующим на целевой машине. У программистов на языках высокого уровня такого доступа нет. Например, если целевая машина содержит бит переполнения, программа на языке ассемблера может проверить его, а программа на языке Java не может. Программа на языке ассемблера может выполнить любую команду из набора команд целевой машины, а программа на языке высокого уровня не может. Короче говоря, все, что можно сделать в машинном языке, можно сделать и на языке ассемблера, но многие команды, регистры и другие объекты недоступны для программиста, пишущего программы на языке высокого уровня. Языки для системного программирования (например С) часто занимают промежуточное положение. Они обладают синтаксисом языка высокого уровня, но при этом с точки зрения возможностей доступа ближе к языку ассемблера. Наконец, программа на языке ассемблера может работать только на компьютерах одного семейства, а программа, написанная на языке высокого уровня, потенциально может работать на разных машинах. Возможность переносить программное обеспечение с одной машины на другую очень важна для многих прикладных программ.
Зачем нужен язык ассемблера?
Язык ассемблера довольно труден. Написание программы на языке ассемблера занимает гораздо больше времени, чем написание той же программы на языке высокого уровня. Кроме того, очень много времени занимает отладка. Но зачем же тогда вообще писать программы на языке ассемблера? Есть две причины: производительность и доступ к машине. Во-первых, профессиональный
программист языка ассемолера может составить гораздо меньшую по размеру программу, которая будет работать гораздо быстрее, чем программа, написанная на языке высокого уровня. Для некоторых программ скорость и размер весьма важны. Многие встроенные прикладные программы, например программы в кредитных карточках, сотовых телефонах, драйверах устройств, а также процедуры BIOS попадают в эту категорию.
Во-вторых, некоторым процедурам требуется полный доступ к аппаратному обеспечению, что обычно невозможно сделать на языке высокого уровня. В эту категорию попадают прерывания и обработчики прерываний в операционных системах, а также контроллеры устройств во встроенных системах, работающих в режиме реального времени.
Первая причина (достижение высокой производительности) является более важной, поэтому мы рассмотрим ее подробнее. В большинстве программ лишь небольшой процент всего кода отвечает за большой процент времени выполнения программы. Обычно 1% программы отвечает за 50% времени выполнения, а 10% программы отвечает за 90% времени выполнения.
Предположим, что для написания программы на языке высокого уровня требуется 10 человеко-лет и что полученной программе требуется 100 секунд, чтобы выполнить некоторую типичную контрольную задачу (Контрольная задача — это программа проверки, которая используется для сравнения компьютеров, компиляторов и т. п.). Написание всей программы на языке ассемблера может занять 50 человеко-лет. Полученная в результате программа будет выполнять контрольную задачу примерно за 33 секунды, поскольку хороший программист может оказаться в три раза умнее компилятора (хотя об этом можно спорить бесконечно). Ситуация проиллюстрирована в табл. 7.1.
Так как только крошечная часть программы отвечает за большую часть времени выполнения этой программы, возможен другой подход. Сначала программа пишется на языке высокого уровня. Затем проводится ряд измерений, чтобы определить, какие части программы отвечают за большую часть времени выполнения. Для таких измерений обычно используется системный тактовый генератор. С его помощью можно узнать, сколько времени затрачивается на каждую процедуру, сколько раз выполняется каждый цикл и т. п.
Предположим, что 10% программы отвечает за 90% времени ее выполнения. Это значит, что из всех 100 секунд работы 90 секунд проводится в этих 10%, а 10 секунд — в оставшихся 90% программы. Эти 10% программы можно усовершенствовать, переписав их на язык ассемблера. Этот процесс называется настройкой (tuning Он проиллюстрирован в табл. 7.1. На переделку основных процедур потребуется еще 5 лет, но время выполнения программы сократится с 90 секунд до 30 секунд. Таблица 7.1. Сравнение программирования на языке ассемблера и на языке высокого уровня (с настройкой и без настройки) Количество человеко-лет, Время выполнения затрачиваемых программы в секундах на написание программы
Сравним этот смешанный подход, в котором используется и язык ассемблера, и язык высокого уровня, с подходом, в котором применяется только язык ассемблера (табл. 7.1). При втором подходе программа работает примерно на 20% быстрее (33 секунды против 40 секунд), но более чем за тройную цену (50 человеко-лет против 15). Более того, у смешанного подхода есть еще одно преимущество: гораздо проще переделать в код ассемблера уже отлаженную процедуру, написанную на языке высокого уровня, чем писать процедуру на языке ассемблера с нуля. Отметим, что если бы написание программы занимало только 1 год, соотношение между смешанным подходом и подходом, при котором используется только язык ассемблера, составляло бы 4:1 в пользу смешанного подхода. Программист, который использует язык высокого уровня, не занят перемещением битов и может так решить задачу, так построить программу, что в конце концов достигнет действительно большого увеличения производительности. А программисты, пишущие программы на языке ассемблера, обычно стараются так построить команды, чтобы сэкономить несколько циклов, поэтому у них такой ситуации возникнуть не может.
Расскажем о двух экспериментах, проведенных во время разработки системы MULTICS. Грехем [49] описал процедуру PL/I, за три месяца переделанную в новую версию, которая была в 26 раз меньше и работала в 50 раз быстрее, чем исходная. Он описал еще одну процедуру PL/L, которая получилась в 20 раз меньше
уперкомпьютеры 10 000000 Предсказание погоды на длительный срок В самой верхней строчке находятся микросхемы, которые приклеиваются на внутреннюю сторону поздравительных открыток для проигрывания мелодий
Happy Birthday», свадебного марша или чего-нибудь подобного. Автор идеи ещее придумал открытки с соболезнованиями, которые играют похоронный марш,о поскольку он выпустил эту идею в потребительскую сферу, вскоре можно бу-
ет ожидать появления и таких открыток. Тот, кто воспитывался на компьютерах
тоимостью в миллионы долларов, воспринимает такие доступные всем компьютеры примерно так же, ка доступный всем самолет. Тем не менее такие компьютеры, не всяких сомнений, должны существовать (а как насчет говорящих мешков для усора, которые просят вас не выбрасывать алюминиевые банки?). Вторая строчка — компьютеры, которые помещаются внутрь телефонов, теле-изоров, микроволновых печей, CD-плейеров, игрушек, кукол и т. п. Через несколь-о лет во всех электрических приборах будут находиться встроенные компьютеры, оличество которых будет измеряться в миллиардах. Такие компьютеры состоят из процессора, памяти менее 1 Мбайт и устройств ввода-вывода, и все это на одной маленькой микросхеме, которая стоит всего несколько долларов. Следующая строка — игровые компьютеры. Это обычные компьютеры с осо-ой графикой, но с ограниченным программным обеспечением и почти полным тсутствием открытости, то есть возможности перепрограммирования. Примерно авны им по стоимости электронные записные книжки и прочие карманные компью-еры, а также сетевые компьютеры и web-терминалы. Все они содержат процессор, несколько мегабайтов памяти, какой-либо дисплей (может быть, даже телевизи-нный) и больше ничего. Поэтому они такие дешевые.
Далее идут персональные компьютеры. Именно они ассоциируются у большин-тва людей со словом «компьютер». Персональные компьютеры бывают двух видов: настольные и ноутбуки. Они обычно содержат несколько мегабайтов памяти, жест-ий диск с данными на несколько гигабайтов, CD-ROM, модем, звуковую карту и другие периферийные устройства. Они снабжены сложными операционными системами, имеют возможность наращивания, при работе с ними используется широкий спектр программного обеспечения. Компьютеры с процессором Intel обычно называются «персональными компьютерами», а компьютеры с другими процессорами — «рабочими станциями», хотя особой разницы между ними нет. Персональные компьютеры и рабочие станции часто используются в качестве сетевых серверов как для локальных сетей (обычно в пределах одной организации), так и для Интернета. У этих компьютеров обычно один или несколько процессоров, несколько гигабайтов памяти и много Гбайт на диске. Такие компьютеры способны работать в сети с очень высокой скоростью. Некоторые из них могут обрабатывать тысячи поступающих сообщений одновременно.
Помимо небольших серверов с несколькими процессорами существуют системы, которые называются сетями рабочих станций (NOW — Networks of Workstations) или кластерами рабочих станций (COW — Clusters of Workstations). Они состоят из обычных персональных компьютеров или рабочих станций, связанных в сеть, по которой информация передается со скоростью 1 Гбит/с, и специального программного обеспечения, позволяющего всем машинам одновременно работать над одной задачей. Такие системы широко применяются в науке и технике. Кластеры рабочих станций могут включать в себя от нескольких компьютеров до нескольких тысяч. Благодаря низкой цене компонентов отдельные организации могут приобретать такие машины, которые по эффективности являются мини-суперкомпьютерами. А теперь мы дошли до больших компьютеров размером с комнату, напоминающих компьютеры 60-х годов. В большинстве случаев эти системы — прямые потомки больших компьютеров серии IBM-360. Обычно они работают ненамного быстрее, чем мощные серверы, но у них выше скорость процессов ввода-вывода и обладают они довольно большим пространством на диске — 1 терабайт и более 12
(1 терабайт=10 байт). Такие системы стоят очень дорого и требуют крупных вложений в программное обеспечение, данные и персонал, обслуживающий эти компьютеры. Многие компании считают, что дешевле заплатить несколько миллионов долларов один раз за такую систему, чем даже думать о том, что нужно будет заново программировать все прикладные программы для маленьких компьютеров. Именно этот класс компьютеров привел к проблеме 2000 года. Проблема возникла из-за того, что в 60-е и 70-е годы программисты, пишущие программы на языке COBOL, представляли год двузначным десятичным числом с целью экономии.
