Опубликовано 06 июля 2004, 00:33

Мультипроцессорность на десктопе

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

Вступление

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

Но почему данный вопрос приобрел актуальность? Дело в том, что производители процессоров для настольных компьютеров не видят путей заметного увеличения производительности одноядерных процессоров. Дальнейшее повышение частоты становится все менее эффективным и все более проблематичным с технологической точки зрения, о чем наглядно свидетельствует отказ компании Intel от нового поколения высокочастотных процессоров с архитектурой NetBurst, не говоря уже о серьезной задержке с ростом частот процессоров Prescott. У AMD бог знает сколько времени частота процессоров топчется в районе 2.2-2.4 ГГц, и совсем не факт, что применение нового 0.09-микронного техпроцесса позволит ее значительно увеличить. У Intel подобного при переходе на такой же техпроцесс не произошло. Зато, что совершенно точно, новый, более тонкий, техпроцесс позволит значительно увеличить количество транзисторов в кристалле, то есть «напихать» туда больше кеш-памяти, больше исполнительных модулей и всего остального. И в том числе – просто разместить на одном кристалле несколько процессорных ядер.

Это было технически возможно довольно давно, и такие многоядерные процессоры выпускаются – например, процессор IBM Power4, – но это решение до сих пор не было достаточно дешевым для настольных систем. С другой стороны, тогда еще не были исчерпаны резервы увеличения частоты, что также делало многоядерные процессоры слишком неэффективными с точки зрения соотношения "цена-производительность" для применения в настольных компьютерах.

Собственно, со стороны Intel несколько лет назад была замечена попытка внедрения многопроцессорных систем на десктопе – выпускались дешевые двухпроцессорные платы под Pentium III и Celeron. И соответствующие процессоры тоже не продавались втридорога. Но по разным причинам от этой идеи отказались в пользу Pentium4 с быстро прирастающей частотой и технологией виртуальной мультипроцессорности Hyper-Threading в перспективе. А настоящие многопроцессорные системы так и остались в другом сегменте рынка.

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

Intel отказалась от NetBurst якобы с расчетом заменить Tejas неким двухъядерным процессором на основе архитектуры Pentium M. Компания AMD давно еще планировала к выпуску процессоры с несколькими ядрами и недавно заявила, что двухъядерный процессор уже разработан и будет выпущен в середине будущего года. Причем его использование будет возможно как в серверах, так и в настольных системах.

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

Ценообразование электронной техники напрямую не связано с себестоимостью производства. Действуют много дополнительных факторов, но все же можно привести иллюстративный пример. Например, 2 ГГц Athlon стоит условно 200 у.е., а 1 ГГц  Duron – 30 у.е. Но первый процессор вовсе не в 6 раз быстрее низкочастотного Duron. В некоторых задачах – хорошо, если в 4 раза окажется быстрее. А в некоторых – и вовсе ровно в два, в соответствии с разницей в частотах.

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

Приложения и мультипроцессорность

Но если бы было все так просто – поставил 10 процессоров по 2 ГГц и получил один в 20 ГГц. В отличие от наращивания частоты, которое пропорционально увеличивает производительность любого приложения (в данном случае допускается некоторое ограничение быстродействия, связанное с производительностью подсистемы памяти), для эффективного использования нескольких процессоров необходимо иметь несколько параллельно работающих программ – независимых или в рамках одного приложения.

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

Итак, для получения прироста производительности от увеличения количества процессоров приложение должно уметь эффективно разделять свою работу между "лошадьми" – процессорными ядрами.

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

Но сначала рассмотрим общие принципы создания многопоточных приложений. Есть два принципиально различных метода или типа параллелизации приложений. Реализации этих двух методов отличаются между собой средней эффективностью и трудозатратами.

Первый метод заключается в том, что каждый из параллельно работающих потоков выполняет одинаковую программу, но с различными данными. Например, есть 100 фотографий, каждую из которых нужно перевести в другой формат – например, сделать черно-белой. Тогда можно разделить работу между двумя программными потоками, первый будет конвертировать первые 50 фотографий, второй - оставшиеся 50. Но в обоих параллельно работающих потоках будет выполняться одна и та же процедура конвертации фотографий.

Второй метод отличается тем, что в различных потоках параллельно исполняются различные процедуры. Например, текстовый редактор, в котором второй поток время от времени сохраняет резервную копию редактируемого текста, в то время как основной поток собственно отвечает за ввод символов. В этом случае потоки выполняют различные процедуры над различными данными. Такой тип распараллеливания называет функциональной декомпозицией, в отличие от декомпозиции данных, используемой в первом методе.

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

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

Для равномерной загрузки работой нескольких потоков можно использовать несколько подходящих приемов – например, случайным образом разделить данные. С большой вероятностью все потоки получат примерно одинаковый объем вычислений. Можно поступить более изощренно, «скармливая» данные потокам по мере их обработки. То есть как только один из потоков обработал свои данные, выдавать ему следующую порцию.

В некоторых случаях можно заранее эффективно разделить данные между потоками. В примере с фотографиями, если известно, что все фотографии одинакового размера и обрабатываются одинаковое время, их можно поделить просто поровну. Таким образом вполне можно добиться практически двукратного прироста производительности при использовании второго процессора.

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

Недостатки метода функциональной декомпозиции

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

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

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

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

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

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

Мультипроцессорность и задачи реалистичного рендеринга

Перейдем, наконец, к рассмотрению конкретных типов приложений. Вооружившись общей теорией, можно ожидать, что особенно большой выигрыш от мультипроцессорности получают приложения, изначально допускающие естественную паралеллизацию с разделением данных. И прекрасным примером такого сорта приложений являются частые гости статей о тестировании новых процессоров – пакеты реалистичного компьютерного рендеринга. Такие, как 3DMax, Light Wave и им подобные.

В частности, именно на них достигается наибольший выигрыш даже от виртуальной мульти процессорности  HyperThreading, что уж говорить о настоящих двух процессорных системах.

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

В отличие от метода обратной трассировки лучей, метод прямой трассировки – или трассировки фотонов – просто моделирует распространение квантов света из источников света по сцене. И те из них, которые попадут в объектив камеры, и сформируют изображение. Таким образом можно получить очень реалистичные картинки.

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

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

Такое богатство способов и обеспечивает относительно легкую параллелизацию такого сорта приложений и высокий прирост производительности.

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

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

Задачи профессионального рендеринга с использованием OpenGL

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

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

Создание же многопоточной версии OpenGL-драйвера – это очень нетривиальная задача, и вряд ли она будет повсеместно решена в ближайшее время. Отладка обычной версии занимает уйму времени, что уж говорить о многопоточной.

Таким образом, приложения данного типа сами по себе не получат большой пользы от нескольких процессоров. Другое дело, что во время визуализации может параллельно работать некая расчетная часть задачи – например, вычислять физические параметры модели или что-то еще. Но, опять-таки, в этом случае трудно эффективно разбить нагрузку между всеми процессорами.

Задачи аудиокодирования и перекодирования

Также популярны в тестовых наборах приложения по кодированию звуковых файлов из одного формата в другой. В данном случае можно смело ожидать хорошего прироста производительности от многопроцессорности. Если больше ничего не приходит в голову, можно просто разделить обрабатываемый файл на несколько частей,и дать каждому процессору свой кусок. Кстати, поддерживающие многопроцессорность программы кодирования получают значительный выигрыш и от технологии Hyper-threading, которая позволяет процессорам Pentium 4 часто побеждать в сравнительных тестированиях, поскольку в данном случае имеет место легкая декомпозиция по данным, которая позволяет эффективно распределить нагрузку между потоками и приблизиться к максимальному приросту производительности.

Задачи архивирования

Процессоры также любят тестировать при помощи программ архивации данных. Хотя некоторые ставят под сомнение актуальность производительности в этих приложениях, тем не менее есть люди, которым совсем нелишня хорошая производительность при архивировании, и это не только компьютерные хакеры, пытающиеся ужать DVD-диск до размера одного CD.

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

Но многопоточные версии архиваторов есть – например, 7-zip, – и они показывают неплохой прирост производительности от дополнительных процессоров, даже и от использования виртуальной многопроцессорности.

Видео кодеки

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

Так или иначе, данные приложения получают хороший прирост от многопроцессорности.

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

Математические задачи

Вопрос выигрыша производительности математических программ по решению уравнений и расчету формул от многопроцессорности достаточно прост. Прирост производительности может быть, а может и не быть – все зависит от задачи. Есть ли метод решения данной задачи, допускающий параллелизацию? Если есть, насколько больше он требует операций по сравнению с обычным? Например, распараллеливаемый метод может требовать в 5 раз большего объема вычислений, и если даже пять процессоров работают одновременно, то никакого прироста производительности не будет. Но если есть 10 процессоров, то прирост производительности будет двукратным.

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

Задачи редактирования двумерных изображений

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

Мультипроцессорность и компьютерные игры

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

Второй момент заключается в том, что производители компьютерных игр традиционно ориентируются на наиболее массовую часть пользователей и начинают использовать какие-то их особенности ("фичи") только в случае их широкой распространенности, иногда даже чересчур перебирая. Это хорошо заметно на примере использования разработчиками игр возможностей видеокарт. Например, когда появилась серия GeForce4, новые чипы предоставляли достаточно большие возможности по части шейдеров и так далее. Но разработчики ориентировались на возможности урезанного, но более массового GeForce4 MX. И даже продвинутые игроки, купившие навороченные видеокарты, так и не дождались толком игр, использующих все их возможности. Потом производители видеоускорителей одумались и перестали урезать дешевые версии по "фичам". Например, теперь Geforce FX 5200, хотя по скорости работы во многих случаях и не особенно превосходит GeForce4, имеет полную поддержку DirectX9.0.

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

Сейчас даже особенно не найти игр, толком задействующих технологию Hyper-Threading, несмотря на то, что уже год как вовсю выпускаются массовые процессоры с ее поддержкой, которые, в том числе, позиционируются как решения для толковых геймеров. Цикл разработки многих современных игр составляет несколько лет, что тоже негативно сказывается на поддержке многопроцессорности.

С другой стороны, типичную компьютерную игру так просто не распараллелить. Отрисовку, как уже обсуждалось, сложно сделать многопоточной – остаются алгоритмы игровой логики, в частности, AI (искусственный интеллект). Вот, допустим, есть какие-то монстры, боты, юниты, и якобы можно интеллект каждого юнита выделить в отдельный программный поток, который будет обсчитываться соответствующим процессором. Но, на самом деле, алгоритмы управления игровыми субъектами очень тесно связаны с остальной игровой логикой и совсем не независимы. Таким образом, разработка многопоточной версии игры достаточно сложна и требует достаточно больших трудозатрат – существенно больших, чем для создания однопоточной версии. И они вполне могут не окупиться с экономической точки зрения. Что толку, если игра будет работать быстрее на некоторых процессорах, но выйдет с большим опозданием? Вспомним, что очень часто игры подготавливаются к выпуску в режиме аврала, ни о какой сложной оптимизации и речи не идет – выпустить бы, чтоб работало. И вспомним большое количество патчей, которые часто сопровождают выход игры – как бы их не стало еще больше. А ведь их стало больше после начала использования видеоускорителей, когда зачастую игра работает только с определенной версией драйверов, а с более старой или более новой отказывается.

Однако не все так совсем плохо с поддержкой многопоточности в играх. Часто игры изготавливаются на основе лицензированного высокотехнологичного игрового движка –  например, множество игр базируется на Quake-движках. И если движок имеет некоторую оптимизацию, то ее автоматически получает и игра. А такой игровой движок может быть хорошо оптимизирован в расчете на все доступные "фичи". Например, тот же движок QuakeIII имел оптимизацию для Pentium 4, и игры на его основе выделялись по производительности на этом процессоре. Графический движок DoomIII, который используется несколькими находящимися в разработке играми, по слухам, умеет использовать многопоточность – в частности, технологию Hyper-threading. И дело здесь, конечно, не в оптимизации самого рендеринга – графический движок Doom должен выполнять большое количество вычислений для построения теневых объемов моделей, необходимых для отрисовки динамических теней. И если очень постараться, то многие вычисления могут быть распараллелены. С учетом того, как долго это движок находится в разработке, у программистов было достаточно времени для необходимых оптимизаций.

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

Еще одна идея использования многопоточности в играх и даже получения прока от Hyper-threading состоит в использовании вспомогательных потоков не для ускорения, а для достижения плавности. Например, пока основной поток занимается перемещением играющего по игровому миру, вспомогательный осуществляет в фоновом режиме загрузку необходимых частей большой карты, чтобы при переходе между уровнями игроку не пришлось ждать долгой загрузки, как во многих играх.

Так что вопрос эффективного использования многопроцессорности в играх не однозначен. Хотя, конечно, пройдет еще очень много времени, пока игры будут получать толковый прирост производительности от нескольких процессоров. Это может даже скорее случиться в секторе приставок. По слухам, новая версия Sony PlayStation будет иметь в составе несколько процессоров. Поскольку разработчики будут иметь конкретную систему для разработки, они могут спокойно использовать все ее возможности.

Мультипроцессорность и шахматы

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

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

Офисные приложения

Для демонстрации возможностей технологии Hyper-threading многие любят тестировать производительность нескольких работающих параллельно офисных приложений. Например, пользователь просматривает сложные веб-сайты, и одновременно происходит сканирование на вирусы. Несколько приложений автоматически позволяют задействовать несколько процессоров и получить прирост производительности. Выходит, что многопроцессорность ускоряет работу с Интернетом. Но это аналогично методу функциональной декомпозиции, и в случае параллельно работающих приложений невозможно в общем случае обеспечить равномерную нагрузку на каждый процессор, поскольку все программы имеют различный объем работы. Правда, когда работающих программ много, в случае если операционная система написана грамотно, она может равномерно нагрузить все процессоры.

Часто говорят, что двухпроцессорные системы гораздо долее чувствительны в смысле реакции на действия пользователя. Бывает, что какое-то приложение заберет все вычислительные ресурсы, и даже мышь медленно реагирует. Может показаться, что двухпроцессорная система сама по себе предпочтительнее любой однопроцессорной. Но это не так. Конечно, два процессора с частотой 1 ГГц лучше одного, но хуже одного с частотой 2 ГГц. Просто несколько легче написать операционную систему, которая бы эффективно распределяла приложения по двум реальным процессорам, чем столь же эффективно использовала один. Операционные системы Windows, установленные в домашних компьютерах, просто не являются так называемыми операционными системами реального времени и не рассчитаны на обеспечение мгновенной реакции. А вообще, в тех случаях когда Windows замирает на гигагерцовом процессоре, можно было бы добиться мгновенной реакции на простейшие действия.

Таким образом, можно ожидать некоторого толка даже от неоптимизированных офисных приложений, если они запускаются параллельно, а операционная система написана грамотно. Но стоит ли это гипотетического удвоения площади кристалла и его стоимости, понять сложно. Другое дело – практически бесплатная с точки зрения производительности технология Hyper-threading. Она и скорость реакции на действия пользователя увеличивает благодаря установке многопроцессорного ядра операционной системы.  Но у нее есть свои минусы – в том числе и те, из-за которых Intel сменила свой Roadmap. К сравнению виртуальной многопроцессорности и реальной многоядерности мы сейчас  перейдем.

Мультиядерность или Hyper-threading

Про технологию Hyper-threading написано достаточно много, известны ее достоинства и недостатки. Несколько деталей можно найти в статье «Обзор архитектуры и особенностей нового Intel Pentium 4 с ядром Prescott». Главное ее достоинство известно – она бесплатная, ее можно просто отключить и все. Hyper-threading требует легкой оптимизации на уровне простой перекомпиляции уже готового многопоточного приложения, но не в этом дело. Максимальный вероятный прирост производительности, оцененный на основании многочисленных тестов реализации данной технологии, составляет 25, а в самом лучшем случае – 35%. В некоторых отдельных редких случаях прирост может быть и больше, но это совсем нетипичные варианты. В некотором количестве тестов многопоточных приложений прирост, наоборот, меньше. Большого прироста трудно было бы и ожидать  ввиду довольно ограниченного количества функциональных устройств, являющихся общими процессорными ресурсами, разделяемыми между двумя потоками.

Но дело в том, что даже этот прирост не гарантирован. Вполне может случиться, что из-за накладных расходов на обслуживание нескольких программных потоков прирост производительности составит всего 10%, что совсем не стоит большой возни с многопоточной версией. Но заранее определить, какой прирост будет в конкретном случае, очень затруднительно.

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

Таким образом, с экономической точки зрения может быть рискованно проводить оптимизацию под HT однопоточного приложения, тем более что HT поддерживают даже не все процессоры, выпускаемые самой Intel. Другое дело, что если приложение уже существует или планируется в варианте для нескольких процессоров, тогда учет некоторых особенностей HT позволит получить прирост и на системе с несколькими виртуальными процессорами.

Эта ситуация с поддержкой HT чем-то слегка напоминает рассмотренную выше ситуацию с "фичами" продвинутых видеокарт, которые так и не использовались разработчиками. Что уж говорить, если в огромном количестве систем еще стоит Windows 98, а там ни о какой HT и речи не идет.

Другое дело – настоящая двухъядерная система. Поскольку в случае успешной оптимизации можно ожидать близкий к двукратному прирост производительности – пусть он может и уменьшиться на несколько процентов из-за накладных расходов и неравномерной нагрузки на процессоры, – возня стоит свеч. Большой гарантированный прирост побудит разработчиков к созданию многопоточных версий даже однопоточных программ. Этого нельзя твердо сказать о технологии Hyper-threading. Поскольку производители процессоров потихоньку берут курс на повышение производительности путем внедрения и виртуальной, и реальной многопроцессорности, им важно приучить разработчиков сразу стараться делать многопоточные приложения.

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

Заключение

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

Но всегда надо помнить, что в каждом отдельном случае рекламный лозунг двухъядерного процессора: "вы покупаете два процессора по цене одного" может означать: "вы покупаете один процессор по цене двух". А может и не означать.