Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Программы Обои   Экспорт RSS E-Books
 
 

  Раздел: Компьютерная документация -> Компьютеры -> Процессоры

 

Каким ты будешь, процессор?

Ну вроде бы ясно - будет введена 64-разрядность, поддержка многопоточности и параллельного выполнения кода, конвейеры будут удлиняться. Однако все ли наследственные признаки хороши, не несут ли они в себе последствий "родовой травмы"? Рассмотрим их по порядку.
64-разрядность

А зачем она нужна? Зачем надо повышать разрядность процессора, ведь еще 486-й мог работать с 64-битными числами, а с добавлением в Pentium инструкций MMX процессоры приобрели возможность манипуляции и с 128 разрядными данными. Как ни странно, 64-битные процессоры работают... медленнее 32-битных. Да-да. 64-битные приложения занимают в ОЗУ гораздо больше места, а значит, и обрабатываются медленней. А если учесть то, что оперативная память по сравнению с кэшами процессора - ресурс медленный и конечный, по крайней мере, на современном этапе... Зачем же нас чуть ли не силком тащат в светлое 64-разрядное будущее, ведь придется переписывать не только все программы, но и операционные системы, и драйверы к ним?

Дело в том, что 64-битный процессор - это не только тот, который выполняет с числами данного разряда все базовые арифметические операции (а не только зашитые в набор дополнительных инструкций). Это еще и тот процессор, который способен этими числами "нумеровать" ячейки памяти. И фактически из-за памяти все и затевалось - чтобы перевалить через барьер в 4294967295 байт (4Гбайт). Но только барьер этот надо преодолеть не в ОЗУ, а в процессоре. Ведь все современные процессоры работают не с физической, а с виртуальной оперативной памятью, то есть программная адресация памяти в реальности не совпадает с действительным расположением ячеек в модулях памяти. Зачем же нужна разрядность 64 бита? А затем, чтобы в многозадачных ОС на логическом уровне можно было сохранить линейность и стройность данных, по-разному пронумеровав ячейки и раздав их разным приложениям. А на самом деле в памяти образуется каша из разных кусков программ и данных, лежащих вперемешку.

Впрочем, все затеивалось не только ради перенумерации ячеек, а ради возможности добавления различных атрибутов для разных ячеек - "только для чтения", "данных нет, загрузить их из свопа на винчестере" и пр. И что, 4 Гбайт не хватало? Увы, да. Во-первых, Windows без разговоров резервирует под свои нужды 2 Гбайт (даже если они ей нафиг не нужны). Во-вторых, некоторые программы некорректно освобождают после своей работы память - в результате в ОЗУ остаются "дырки", непригодные к использованию другими программами. В-третьих, программа может держать файл не в свопе на винчестере, а в ОЗУ - работа с такими данными ускоряется, но если это какая-нибудь база данных, то остальные программки резко переходят на положение "бедных родственников".

Но 64-битный режим - это не просто улучшенная версия 32-битного, а фактически следующая версия архитектуры процессоров x86. Наконец-то удалось удвоить количество регистров общего назначения (из которых собственно и состоит тело инструкции - скармливается процессору и говорит, что делать с данными) с 8 до 16 штук. Раньше в этом отношении i8086 ничем не отличался от Pentium 4/Athlon ХР, и было это не прихотью разработчиков, а фундаментальным ограничением самого набора инструкций x86 (каждая инструкция состояла из 4 частей - 2 трехбитных и 2 однобитных, отсюда и восьмерка). Затем исключили давно не используемые режимы типа имитации современным процессором древнего i8086 (режим Virtual 8086). Теоретически новые регистры добавлены так, чтобы сохранилась возможность выполнять 32-битный код, но на практике это не всегда оказывается реально выполнимым.
Конвейер

Даже очень древний процессор i8086 содержал своеобразный двухстадийный конвейер - выборка новых инструкций и их исполнение осуществлялись независимо друг от друга, что значительно ускоряло обработку инструкций. Плюс подъем тактовой частоты, а значит, еще большее ускорение исполнения кода. Хорошо? Замечательно. Однако конвейерное выполнение команд вносит свои проблемы: процессор делится на блоки, занимающиеся декодированием инструкций, и собственно блоки их исполнения. Поскольку время исполнения инструкций может сильно варьироваться, приходится создавать специальный механизм "диспетчеров", которые могли бы блокировать (или накапливать в специальном месте) выборку и декодирование новых блоков инструкций. Плюс когда в программном коде происходит разветвление (условный переход) и неизвестно, какая из веток кода будет правильной, - вычисляются обе, а потом "лишняя" сбрасывается. Дополнительно вводится блок предсказания переходов, который хранит в специальном кэше результаты ранее правильно вычисленных переходов, чтобы с большей вероятностью предсказать правильный путь. Появилась необходимость специального планировщика, который просматривает код, находит зависимые друг от друга участки...

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

А что же в реальности (если не рассматривать случаи оптимизированного кода)? У AMD в процессорах с архитектурой K8 за такт исполняется в среднем 3 инструкции. Исполнение каждой инструкции разбивается на 10-20 стадий - сначала идет выборка 3 инструкций, одновременно инструкции "тегируются" (расставляются пометки о том, в каком порядке они стоят) и отправляются в блоки декодирования - простые в простой (DirectPath), сложные - в сложный (VectorPath). Эти блоки, декодируя команды, заодно их еще и перетасовывают наиболее эффективным для исполнения образом. Далее декодированные во внутренние микроинструкции данные тройками внутреннего микрокода поступают к Instructions Control Unit, который накапливает данные в очередь для безостановочной поставки на конвейер. Происходит вычисление.

У Intel в процессорах с архитектурой NetBurst за такт исполняется в среднем 2 инструкции. Исполнение каждой разбивается на 20-30 стадий. Сначала инструкции попадают в декодер, который вынесен за пределы конвейера и работает на половинной частоте ядра (для его загрузки требуется дополнительно 15-30 тактов, то есть фактически конвейер в 2 раза длиннее, чем пишут в пресс-релизах). Тут еще на стадии копирования кода в кэш-память убираются безусловные и предсказываются условные переходы, а также выполняется множество других операций по преобразованию исходного кода во внутренний оптимизированный к исполнению микрокод. В результате в теории процессор может за такт исполнять до 4 инструкций, но стоит ему вылететь на незакэшированный участок, и удастся выполнить в лучшем случае одну.

А дальше работа конвейера - еще раз проверяется правильность выбора направления условного перехода, затем полученный внутренний микрокод по 6 инструкций (дважды по 3 инструкции за такт) складывается в очередь выборки, чтобы сгладить неравномерность поступления данных. Но из-за большой длины конвейера и латентности кэшей, подготовки/переименования регистров на это уходит 5-10 тактов. И только после этого тройки микроинструкций начинают поступать на выполнение - сначала к планировщикам, работу которых переупорядочивают так называемые диспетчеры (аж 7 штук). Их задача состоит в том, чтобы на исполняющее устройство одновременно пришли данные для обработки и связанная с ними микрооперация. А если не сложилось - тогда происходит replay - информация отправляется раз за разом в подобие специального кэша, пока данные и нужная для них операция не прибудут одновременно. В результате реплеи могут забить все время работы диспетчера, почти блокируя поступление новых данных. Более того, информация, циркулирующая в реплеях, может вообще зациклиться.

Зачем надо было создавать такого монстра? Убедившись в невозможности синхронизировать длинный конвейер, решили не сокращать его, а сделать работу его частей сознательно асинхронной и таким образом еще больше поднять частоту процессора. Думали, что частота все спишет. Поначалу так и было, но потом реплеи стали не только тормозить, но еще и перегревать процессор.
Параллельность

На серверном рынке, где как раз и распространены многопроцессорные системы, можно заметить поразительную картину. Если брать среднюю стоимость на один процессор (при равном объеме ОЗУ, одинаковой поддержке 32/64-разрядных приложений и т.д.), то выяснится, что процессор в истинной многопроцессорной системе стоит в 5-8 раз дороже, чем такой же его собрат в кластере (к тому же имеющий частоту, вдвое большую). Неужели такая высокая плата берется за престиж? И как еще такие монстры не вымерли в наш век бурного роста сетевых технологий и распределенных вычислений? Не вымрут - и для этого есть веские причины, которые объясняются большей производительностью многопоточных вычислений над параллельными. Поясню:

1. Симметричные многопроцессорные системы (SMP) - все процессоры объединены быстрой межпроцессорной шиной, общее для всех ОЗУ плюс крайне сложная и дорогая система софта и железа, заставляющая работать этого монстра как единое целое. Вдобавок головная боль с охлаждением - шкаф серверной стойки, нагруженный процессорами и ОЗУ (вроде BlueGene от IBM), греет воздух с производительностью тепловой пушки для обогрева складских помещений. Вычисления многопоточные, параллельными они становятся лишь вынужденно, и этого пути старательно избегают.

2. Кластеры - обычные ПК или серверы, поставленные рядком на металлическую стойку и соединенные между собой при помощи высокоскоростных интерфейсов (обычно это простые сетевые 10/100 Gigabit Ethernet-карточки, хотя есть и специализированные среды передачи данных - InfiniBand, Beowulf, Myrinet, Quadrics). Плюс компьютер, который координирует и раскидывает вычисления по разным кусочкам кластера, который должен быть связан с каждым узлом по топологии "звезда" и из-за высокой латентности при передаче данных является самым узким местом. Проблему пытаются решить путем создания узлов, где центральный компьютер связан только с несколькими, и уже эти избранные отдают его приказы дальше, образуя своеобразные узлы подчинения. Это позволяет одновременно передавать множество данных и сокращать время реакции системы на управляющие команды. Вычисления параллельные, лишь в образованных подузлах их удается сделать многопоточными.

3. Распределенные вычисления - используются обычные ПК, связанные обычными же локальными сетями. Наиболее ярким примером служат различные сети GRID-вычислений, когда расчеты ведутся только в то время, когда ПК не нужен его хозяину. Но все плюсы такого подхода уравновешиваются возникающими при этом минусами - компьютеры разнородные (как по железной, так и по программной составляющей), разная пропускная способность и нестабильность каналов, наличие "лишних" (выполняемых одновременно с расчетами) задач, непредсказуемое поведение элементов системы (пользователь может в любой момент отключить свой узел, поэтому одни и те же расчеты приходится дублировать на разных узлах). Вычисления только параллельные.

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

Своеобразный переворот в среде многопроцессорных вычислений готовит неугомонная AMD. Мало ей того, что процессоры Opteron все активнее вытесняют чипы Itanium 2 (по данным последнего Top500 самых производительных компьютеров, продукция Intel получила 46 мест вместо прежних 79, а AMD - 55 вместо 25).

Напомню, что два 2-процессорных сервера AMD могут работать независимо друг от друга или в виде единого 4-процессорного кластера именно благодаря грамотно реализованной шине HyperTransport. Эта шина, изначально заложенная в ядро процессора и позволяющая работать с ОЗУ любого процессора как с общей памятью, обеспечивает фактически столь же высокую производительность, что и SMP-системы, и именно это дало AMD возможность существенно потеснить Intel на серверном рынке. Однако AMD на этом не остановилась - к выпуску готовится чип Chorus, который будет соединять от 2 до 4 процессоров по шине HyperTransport и к трем другим компьютерам по межпроцессорной шине типа InfiniBand. В результате (напомню, ОЗУ - общее) мы получаем производительность истинной SMP-системы при гораздо более легком монтаже и незначительном ценовом бремени.
Многопоточность

Помогают параллельные и многопоточные вычисления ускорить работу процессора? Вроде бы да. Но беда параллельного исполнения в том, что процессор сам не может раскидать код на два потока и более - за него это должен сделать программист. Нет, можно, конечно, не раскидывать, но тогда и увеличения скорости не будет, сколько бы ядер у процессора ни было. Хочется поднять производительность? Да. А как? А вот как: в программе при помощи специальных параметров вызова образуется несколько точек исполнения, которые дробят код на потоки (исполняемые параллельно и независимо друг от друга), а после исполнения они перемещаются к новой точке исполнения.

И что же здесь сложного? Ведь есть специальные библиотеки (вроде OpenMP.dll), которые на этапе компиляции кода расставляют фактически в автоматическом режиме метки распараллеливания кода для процессора -потом на отладчике (Intel Thread Checker) в визуальном режиме можно посмотреть, где куски кода конфликтуют за одни и те же ресурсы ядер процессора, - и многопоточный код готов. Но... Кто ж знал, что на дороге к светлому будущему быстрого исполнения кода столько оврагов?

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

Овраг 2. Необходимость балансировки загрузки потоков, иначе "быстро" вычисленный поток будет вынужден дожидаться исполнения отстающего, и вместо двукратного повышения производительности мы получим лишь несколько процентов прибавки скорости.

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

Мало того, роется новая яма, так называемый dead-lock. В описанном выше случае он выглядит так: камень попадает в стекло, и программа определяет, что она должна разбить стекло и размазанную по нему каплю воды. Но капля не дает изменить стекло - она ждет, когда камень изменит стекло, чтобы она могла размазаться не по всему стеклу, а по одному только осколку, и "не отдает" стекло на изменение. Снова вылет программы с ошибкой. А если при этом поток капли (или камня) "забыл" снять блокировку с изменяемого им объекта? Представляете себе процесс отладки такого приложения? А теперь вообразите, что будет, если действие одного потока сопровождается десятком действий другого? А если события не четко детерминированы и проявляются крайне редко?
Так каким же должен быть процессор?

Поддержка 64-разрядов - это спорно? Да. Писали бы нормальный код - обошлись бы без нее. Конвейер? Ну, это вообще монстр - у AMD поменьше, у Intel побольше, вот и вся разница. Параллельные и многопоточные приложения? Да, за ними будущее, но нервов они нам потеребят немало, это ясно уже сейчас.

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

И этим путем уже шли. Процессор Advanced RISC Machines версия 2 (или ARM2) имел 30 тыс. транзисторов, оперировал 32 разрядами и был более производителен, чем i286, имевший 120 тыс. транзисторов и оперировавший вдвое меньшим количеством разрядов. Но ему и его потомкам достался лишь рынок бытовых устройств и наладонников.

А кто этим путем идет сейчас? Давайте-ка оглянемся. Вышедшая Xbox 360 от Microsoft базируется на PowerPC от IBM (трехядерный, 64-разрядный, 3,2 ГГц, общий кэш L2 1 Мбайт, 165 млн транзисторов, техпроцесс 90 нм). Sony с PlayStation3 обещают выйти в январе, а Nintendo Revolution в мае - но и они основаны на процессорах Голубого Гиганта.

Sun представила восьмиядерный процессор UltraSPARC T1 (ранее Niagara) с очень низким энергопотреблением, но это лишь вариация на тему чипов Athlon и Pentium. А вот Cell (ранее Broadband Processor) - это попытка пересмотреть существующие парадигмы программирования в сторону полной абстракции данных. Здесь нет данных, нет программ, нет процессоров - есть только код в виде данных или код, который их обрабатывает (программный или абстрактно аппаратный).

В результате все написанные программы получаются параллельными по самой своей сути. Мало того, такая система крайне легко масштабируется вплоть до суперкомпьютера. При этом ячейки-процессоры Cell могут быть встроены не только в материнскую плату ПК, но и в любую бытовую технику (главное, чтобы все элементы были взаимосвязаны). Cell - девятиядерный процессор, 8 ядер которого - это на самом деле 286-е процессоры с кусочком собственной ОЗУ, выполненные в современных технологических нормах и разогнанные до частоты в 3,2 ГГц плюс 1 PowerPC-подобное ядро, которое всем этим оркестром и дирижирует.

Что же мешает наступлению этого радужного будущего? Как всегда, грустное настоящее - отсутствие ОС, доступных компиляторов, средств разработки и минимальное количество перенесенного на новую среду ПО. И не только - продукция IBM для реализации своего потенциала требует соответствующих комплектующих. Например, для Xbox 360 поставляются GDDR3-память 512 Мбайт, 700 МГц (самый дорогой компонент приставки), а для двухпроцессорных серверов на базе IBM Cell используется память Rambus eXtreme Data Rate. А это требует денег. И, главное, при таком подходе необходима грамотная и очень тщательная оптимизация кода, когда распараллеливанием занимается не программа в автоматическом режиме, а программист. Причем программист, который "дружит" со своей головой, а не только с мышкой и клавиатурой.

Кто-то может возразить, что переход компьютеров Macintosh на процессоры Intel связан с тем, что у IBM нет высокопроизводительных процессоров. Дело не этом, а в отсутствии у IBM системы "принудительного" управления цифровыми правами типа Palladium и иже с ними.

Автор: Анатолий Ковалевский
Источник: www.listzone.ru

Ссылки по теме
Двухъядерные процессоры Intel: выбираем лучший. Часть первая
Двухъядерные процессоры Intel: выбираем лучший. Часть вторая
Извечный вопрос: Intel или AMD?
Игровой турнир: Интел против AMD
Многоядерные процессоры: первые попытки

Вся документация процессоры

 

Компьютерная документация от А до Я - Главная

 

 
Интересное в сети
 
10 новых программ
CodeLobster PHP Edition 3.7.2
WinToFlash 0.7.0008
Free Video to Flash Converter 4.7.24
Total Commander v7.55
aTunes 2.0.1
Process Explorer v12.04
Backup42 v3.0
Predator 2.0.1
FastStone Image Viewer 4.1
Process Lasso 3.70.4
FastStone Image Viewer 4.0
Xion Audio Player 1.0.125
Notepad GNU v.2.2.8.7.7
K-Lite Codec Pack 5.3.0 Full


Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
Реклама на сайте. Размещая рекламу у нас, вы получите новых посетителей, которые могут стать вашими клиентами.
 
Это интересно
 

Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.