Сила есть - ума надо. На пути к параллельным системам.
-Что нужно, чтобы увеличить производительность ПО на многоядерных процессорах?- Отключить лишние процессоры!Это не анекдот, а сермяжная правда из жизни компьютеров. Многие, в погоне за многоядерными мощностями, не понимают, что получают взамен потраченных на дорогие компьютеры денег. В первую очередь это проблемы, т.к. стандартный софт (так будем называть 99% существующего ПО) начинает работать непредсказуемо. Во вторую - понижение производительности.
«Опять СпецЛаб мутит воду», - пойдет новая волна гулять по миру. Уж простите нас, такие мы непутевые по жизни! Не критикуйте сурово! Но прогресс несет новые задачи, и надо адекватно реагировать. Увы, большинство программистов не сильно вникает в суть многоядерности. Некоторые вообще уверены, что главным козырем здесь является многопоточность. Полтора года назад примерно также думали и у нас. Многопоточность действительно приносила плоды, пока ядер было только два. Операционная система, как могла, разруливала потоки, но, поскольку программный код не был изначально рассчитан на работу сразу с двумя ядрами, второе использовалось лишь на 30% от своих возможностей. На 4-х процессорах и более даже этот фокус уже не пошел. Через пару часов высоконагруженной работы на таком компьютере производительность системы «Скиф» падает более чем на 30% по сравнению с тем, что было на двух ядрах. Интерфейс начинает тормозить и с трудом откликается на команды пользователя. Полтора года назад наши программисты схватились за голову – программа «Скиф» не в состоянии работать на многопроцессорных системах. Прощай перспектива!
«На протяжении длительного времени прогресс в области микропроцессоров фактически отождествлялся со значением тактовой частоты. В 2001 году в корпоративных планах производителей микропроцессоров значилось, что уже к концу десятилетия будет преодолен барьер 10 ГГц. Увы, планы эти оказались неверны. О параллелизме, как о светлом будущем компьютерных систем, ученые упорно говорили на протяжении всех последних 30-35 лет. Однако до тех пор, пока преодоление связанных с этим сложностей, например с необходимостью разделения приложений на потоки, компенсировалось непрерывно возрастающей производительностью процессоров, никто из производителей по понятным причинам инвестировать в эту перспективу не хотел. Поэтому до появления многоядерных процессоров параллельные вычисления оставались атрибутом суперкомпьютеров. Многолетнее игнорирование очевидного привело к тому, что, когда час пробил, оказалось, увы, к светлому будущему индустрия не готова, хотя, конечно же, есть отдельные острова готовности, не более того». (Леонид Черняк «ОС»).
Нынешнее состояние дел в области параллельного программирования и сопутствующих технологий, хотя и неплохо описано в теории, пока не предлагает большого выбора инструментальных средств. Пара библиотек (одна от Интел, другая от Майкрософт) только вносят сумбур своими фундаментальными отличиями. Но обе конторы наоткрывали бренчей, которые занимаются распараллеливанием кода. Стоимость услуги начинается от миллиона долларов. Надежда, как всегда, на свои таланты: родных ивановских математиков–программистов, которые, правда, доросли до официального звания лучших в мире (получено в Париже). Ну, это я так, чтобы вы не думали, что все на коленках делается.
К сожалению, руководство запретило использовать непонятные непрограммисту термины, поэтому я не буду приводить все детали схем Фон Неймана, которые программисты СпецЛаб перелопатили за эти полтора года, главное, что получен положительный результат, и он, ко всему прочему, работает на практике – проверено на людях. Наверное, как и со случаем выпуска СпецЛабом первой платы PCI-Express, многие будут говорить «этого не может быть», но и она тоже работает без сбоев вот уже много лет. Причем с 5-и летней гарантией.
Так вот, в многопоточных приложениях есть один очень сложно преодолимый изъян: все процессоры используют одни и те же ресурсы. Работа с общими данными ведет не к увеличению, а к уменьшению производительности. Когда сразу несколько потоков пытаются получить доступ к одному и тому же сегменту памяти, что получается? Правильно, они встают в очередь, но только в случае с однопроцессорной архитектурой. А когда процессоров много, и все они независимы, мы получаем… Дальнейшее можно пропустить, обещаю, что больше ругаться не буду.
Мы получаем дедлок (англ. deadlock, что на русский можно перевести как «взаимная блокировка») - это ситуация, когда несколько процессов или потоков, взаимно заблокировав друг для друга доступ к некому общему для них всех ресурсу, бесконечно долго ожидают его освобождения. Простейший пример: у нас есть два процесса (или потока) и два ресурса, доступ к которым каждый из потоков намерен захватить. Первый поток захватывает один ресурс, второй - оставшийся, и, выполнив какие-то действия с этими ресурсами, потоки начинают ожидать, когда освободится второй из нужных для них ресурсов.
Или предположим, что у вас есть два объекта: объект a класса ValueHolder и объект b другого класса, реализующего интерфейс Listener. В реализации метода b. valueChanged() может происходить все, что угодно, в том числе попытка захвата какой-либо блокировки Z. При этом если эта попытка завершится неудачно, то поток будет остановлен, а блокировка объекта a не будет освобождена. Тем временем другой поток, удерживающий блокировку Z, может попытаться вызвать метод addListener() объекта a, однако для этого ему нужно будет захватить блокировку на этот объект, но она удерживается первым потоком. Таким образом, оба потока будут находиться в состоянии бесконечного ожидания и нет никакой надежды, что эта ситуация как-нибудь разрешится. Такой вид дедлоков часто скрывается в программах, использующих мониторы и, разумеется, проявляют себя такие ошибки в самый неподходящий момент.
Проще говоря, процессоры борются между собой за доступ к данным. При этом если в программе не прописаны правила борьбы, она становится нестабильной. Поэтому, если вы используете обычный софт (нескольколетней давности), примите совет: отключайте дополнительные процессоры, благо Windows предоставляет такую возможность (прямо в Диспетчере задач).
Более продвинутые программисты уже наделали заплаток к своим программам, и зрительно не все так плохо. К тому же пользователь никогда не знает, что есть «лучше». Так называемые «программные блокировки» блокируют работу с разделяемой памятью при обращении к ней одним процессором во время того, как она занята каким-нибудь другим. В результате мы имеем явление, называемое «гонкой данных» (data race), при котором образуются еще большие очереди, нежели на одном процессоре. Чем дольше программа так работает, тем больше фрагментация памяти. Чем больше фрагментация, тем еще больше очереди. Неудивительно, что производительность падает.
Хотя неискушенному зрителю все можно представить с точностью наоборот. Т.к. дополнительные «процы» дружно стоят в очереди, то их загрузка стремится к нулю. В Диспетчере задач операционной системы вам наглядно продемонстрируют, как слабо грузятся процессоры программой. Труднее объяснить только, почему сама программа при таких мощностях так страшно тормозит. Силы много – ума бы надо.
Да и надежность все равно страдает. Последний раз выругаюсь: «Основная проблема, сопровождающая блокировки, заключается в том, что не существует точных указаний, как их следует делать, все определяется избранной программистом дисциплиной, он должен помнить о существовании соответствующих блокировок при обращении к тем или иным данным. Кроме того, блокировки плохо поддаются локализации, поэтому все, кто обращаются к данным, должны помнить о них и учитывать факт их существования. Так, решая в лоб задачу, например, о птичках, клюющих некоторое число зернышек в единицу времени, вы не сможете получить однозначный ответ на вопрос, сколько же зернышек они склюют за заданное время? То, что решается просто и естественно в рамках начальной школы, требует от незаурядного программиста неадекватных уровню сложности задачи усилий».
Для специалистов полезно было бы ознакомиться с трудами Эдварда А. Ли и Карла Хьюитта.
Но не будем запудривать мозги бедному пользователю теоретизмами, скажем о главном. Компания активно проповедует правдивость и откровенность, поэтому без муара. Конечно, ничего сверхъестественного программисты СпецЛаба не сотворили, просто (если в данном случае это слово подходит) они переписали код программы так, что теперь каждый процессор в каждый момент времени работает со своим собственным автономным фрагментом данных. По сути, на каждую задачу существует инструкция, кому к каким блокам памяти обращаться. Правда, эта простота немного соответствует подвигу, ведь пришлось полностью перелопатить весь код программы. Но нет худа без добра: заодно были поправлены многие редко встречаемые ошибки. И таким образом, как и в 90-х в России, была решена проблема очередей – в данном случае процессорных очередей. В системе GOALcity Pegal они больше не борются за каждый блок памяти. Каждому – по производительности!
Достаточно сегодня глянуть на релиз «Пегаль» в «полной выкладке». При небольшой (30%) и равномерной загрузке процессоров I7 он выводит и пишет 20 каналов «живого» видео в полном разрешении и цвете. Больше пока не позволяют платы, но этот вопрос поправим. При этом в полном объеме обеспечиваются ресурсами многочисленные сетевые клиенты. Аппаратная компрессия вновь неактуальна!
Даже на массовых 4-х ядерных системах предыдущего поколения вы получите ощутимую прибавку производительности в «Пегали», а сегодня уже в свободной продаже доступны процессоры следующего поколения, способные выполнять 2 потока на каждом ядре, что для 4-х ядер дает 8 параллельно исполняемых потоков. В ближайшее время количество ядер достигнет 8-и, а потоков, соответственно, - 16-и… Профессор Массачусетского технологического института Ананд Агарвал, один из крупнейших современных специалистов по процессорным архитектурам, считает: «При сегодняшних одном–восьми ядрах в начале следующего десятилетия их число превысит 1000. Многоядерные системы станут столь мощной силой, что разрушат сложившуюся стабильную обстановку и заставят проектировщиков переосмыслить фундаментальные начала».
Другой, не менее известный ученый, Саттер уверен: «Многоядерные машины - наше неизбежное будущее, а потому главная задача заключается в необходимости научиться программировать для них. Новые компьютеры будут все более и более производительными, но программирование не сможет далее развиваться за счет умения «оседлать волну производительности». Основное направление развития параллелизм.
И снова революция, господа! На этот раз «параллельная» - Concurrency Revolution. Мы рады сообщить, что одной из первых революционных программ в области безопасности стала GOALcity Pegal. И забросайте нас шапками! Как бы вы ни критиковали эту статью, даем прогноз, что через пару лет все начнут перестраиваться под все более наращиваемые мощности многопроцессорных систем.
Основные выводы.
1. Что может произойти со стандартной программой, не оптимизированной для работы на многопроцессорных (многоядерных) платформах:
- Второе ядро увеличивает производительность лишь на 30%, хотя вы платите за полный кристалл. Это все равно, что вам не довешивают 70 граммов на каждые 100.
- Каждый следующий процессор может не увеличить, а уменьшить производительность.
- Применение более двух процессоров способно дестабилизировать, а в некоторых случаях полностью парализовать работу программы.
2. По всей видимости, через пару лет сегодняшний софт на старых принципах исполнения кода придется выкинуть.
3. Разработчикам ПО стоит задуматься о параллельном программировании уже вчера, т.к. многопроцессорные системы активно продаются уже сегодня.
4. Параллельное программирование увеличивает мощности компьютерных систем в десятки, а завтра и в сотни раз.
«Большинство многопоточных приложений содержат ошибки, связанные с параллельным исполнением потоков, я считаю, что можно выдвинуть следующую гипотезу – как только многоядерные системы станут широко используемыми, скрытые ошибки в многопоточных программах станут все чаще и чаще проявлять себя, приводя к падению ранее надежных систем. Такой вариант развития событий выглядит особенно удручающим с точки зрения производителей вычислительных систем – следующее поколение ПК будет характеризоваться в сознании потребителя как поколение компьютеров, на которых перестали нормально работать программы, замечательно выполнявшие свои функции на старых компьютерах».
«На протяжении длительного времени прогресс в области микропроцессоров фактически отождествлялся со значением тактовой частоты. В 2001 году в корпоративных планах производителей микропроцессоров значилось, что уже к концу десятилетия будет преодолен барьер 10 ГГц. Увы, планы эти оказались неверны. О параллелизме, как о светлом будущем компьютерных систем, ученые упорно говорили на протяжении всех последних 30-35 лет. Однако до тех пор, пока преодоление связанных с этим сложностей, например с необходимостью разделения приложений на потоки, компенсировалось непрерывно возрастающей производительностью процессоров, никто из производителей по понятным причинам инвестировать в эту перспективу не хотел. Поэтому до появления многоядерных процессоров параллельные вычисления оставались атрибутом суперкомпьютеров. Многолетнее игнорирование очевидного привело к тому, что, когда час пробил, оказалось, увы, к светлому будущему индустрия не готова, хотя, конечно же, есть отдельные острова готовности, не более того». (Леонид Черняк «ОС»).
Нынешнее состояние дел в области параллельного программирования и сопутствующих технологий, хотя и неплохо описано в теории, пока не предлагает большого выбора инструментальных средств. Пара библиотек (одна от Интел, другая от Майкрософт) только вносят сумбур своими фундаментальными отличиями. Но обе конторы наоткрывали бренчей, которые занимаются распараллеливанием кода. Стоимость услуги начинается от миллиона долларов. Надежда, как всегда, на свои таланты: родных ивановских математиков–программистов, которые, правда, доросли до официального звания лучших в мире (получено в Париже). Ну, это я так, чтобы вы не думали, что все на коленках делается.
К сожалению, руководство запретило использовать непонятные непрограммисту термины, поэтому я не буду приводить все детали схем Фон Неймана, которые программисты СпецЛаб перелопатили за эти полтора года, главное, что получен положительный результат, и он, ко всему прочему, работает на практике – проверено на людях. Наверное, как и со случаем выпуска СпецЛабом первой платы PCI-Express, многие будут говорить «этого не может быть», но и она тоже работает без сбоев вот уже много лет. Причем с 5-и летней гарантией.
Так вот, в многопоточных приложениях есть один очень сложно преодолимый изъян: все процессоры используют одни и те же ресурсы. Работа с общими данными ведет не к увеличению, а к уменьшению производительности. Когда сразу несколько потоков пытаются получить доступ к одному и тому же сегменту памяти, что получается? Правильно, они встают в очередь, но только в случае с однопроцессорной архитектурой. А когда процессоров много, и все они независимы, мы получаем… Дальнейшее можно пропустить, обещаю, что больше ругаться не буду.
Мы получаем дедлок (англ. deadlock, что на русский можно перевести как «взаимная блокировка») - это ситуация, когда несколько процессов или потоков, взаимно заблокировав друг для друга доступ к некому общему для них всех ресурсу, бесконечно долго ожидают его освобождения. Простейший пример: у нас есть два процесса (или потока) и два ресурса, доступ к которым каждый из потоков намерен захватить. Первый поток захватывает один ресурс, второй - оставшийся, и, выполнив какие-то действия с этими ресурсами, потоки начинают ожидать, когда освободится второй из нужных для них ресурсов.
Или предположим, что у вас есть два объекта: объект a класса ValueHolder и объект b другого класса, реализующего интерфейс Listener. В реализации метода b. valueChanged() может происходить все, что угодно, в том числе попытка захвата какой-либо блокировки Z. При этом если эта попытка завершится неудачно, то поток будет остановлен, а блокировка объекта a не будет освобождена. Тем временем другой поток, удерживающий блокировку Z, может попытаться вызвать метод addListener() объекта a, однако для этого ему нужно будет захватить блокировку на этот объект, но она удерживается первым потоком. Таким образом, оба потока будут находиться в состоянии бесконечного ожидания и нет никакой надежды, что эта ситуация как-нибудь разрешится. Такой вид дедлоков часто скрывается в программах, использующих мониторы и, разумеется, проявляют себя такие ошибки в самый неподходящий момент.
Проще говоря, процессоры борются между собой за доступ к данным. При этом если в программе не прописаны правила борьбы, она становится нестабильной. Поэтому, если вы используете обычный софт (нескольколетней давности), примите совет: отключайте дополнительные процессоры, благо Windows предоставляет такую возможность (прямо в Диспетчере задач).
Более продвинутые программисты уже наделали заплаток к своим программам, и зрительно не все так плохо. К тому же пользователь никогда не знает, что есть «лучше». Так называемые «программные блокировки» блокируют работу с разделяемой памятью при обращении к ней одним процессором во время того, как она занята каким-нибудь другим. В результате мы имеем явление, называемое «гонкой данных» (data race), при котором образуются еще большие очереди, нежели на одном процессоре. Чем дольше программа так работает, тем больше фрагментация памяти. Чем больше фрагментация, тем еще больше очереди. Неудивительно, что производительность падает.
Хотя неискушенному зрителю все можно представить с точностью наоборот. Т.к. дополнительные «процы» дружно стоят в очереди, то их загрузка стремится к нулю. В Диспетчере задач операционной системы вам наглядно продемонстрируют, как слабо грузятся процессоры программой. Труднее объяснить только, почему сама программа при таких мощностях так страшно тормозит. Силы много – ума бы надо.
Да и надежность все равно страдает. Последний раз выругаюсь: «Основная проблема, сопровождающая блокировки, заключается в том, что не существует точных указаний, как их следует делать, все определяется избранной программистом дисциплиной, он должен помнить о существовании соответствующих блокировок при обращении к тем или иным данным. Кроме того, блокировки плохо поддаются локализации, поэтому все, кто обращаются к данным, должны помнить о них и учитывать факт их существования. Так, решая в лоб задачу, например, о птичках, клюющих некоторое число зернышек в единицу времени, вы не сможете получить однозначный ответ на вопрос, сколько же зернышек они склюют за заданное время? То, что решается просто и естественно в рамках начальной школы, требует от незаурядного программиста неадекватных уровню сложности задачи усилий».
Для специалистов полезно было бы ознакомиться с трудами Эдварда А. Ли и Карла Хьюитта.
Но не будем запудривать мозги бедному пользователю теоретизмами, скажем о главном. Компания активно проповедует правдивость и откровенность, поэтому без муара. Конечно, ничего сверхъестественного программисты СпецЛаба не сотворили, просто (если в данном случае это слово подходит) они переписали код программы так, что теперь каждый процессор в каждый момент времени работает со своим собственным автономным фрагментом данных. По сути, на каждую задачу существует инструкция, кому к каким блокам памяти обращаться. Правда, эта простота немного соответствует подвигу, ведь пришлось полностью перелопатить весь код программы. Но нет худа без добра: заодно были поправлены многие редко встречаемые ошибки. И таким образом, как и в 90-х в России, была решена проблема очередей – в данном случае процессорных очередей. В системе GOALcity Pegal они больше не борются за каждый блок памяти. Каждому – по производительности!
Достаточно сегодня глянуть на релиз «Пегаль» в «полной выкладке». При небольшой (30%) и равномерной загрузке процессоров I7 он выводит и пишет 20 каналов «живого» видео в полном разрешении и цвете. Больше пока не позволяют платы, но этот вопрос поправим. При этом в полном объеме обеспечиваются ресурсами многочисленные сетевые клиенты. Аппаратная компрессия вновь неактуальна!
Даже на массовых 4-х ядерных системах предыдущего поколения вы получите ощутимую прибавку производительности в «Пегали», а сегодня уже в свободной продаже доступны процессоры следующего поколения, способные выполнять 2 потока на каждом ядре, что для 4-х ядер дает 8 параллельно исполняемых потоков. В ближайшее время количество ядер достигнет 8-и, а потоков, соответственно, - 16-и… Профессор Массачусетского технологического института Ананд Агарвал, один из крупнейших современных специалистов по процессорным архитектурам, считает: «При сегодняшних одном–восьми ядрах в начале следующего десятилетия их число превысит 1000. Многоядерные системы станут столь мощной силой, что разрушат сложившуюся стабильную обстановку и заставят проектировщиков переосмыслить фундаментальные начала».
Другой, не менее известный ученый, Саттер уверен: «Многоядерные машины - наше неизбежное будущее, а потому главная задача заключается в необходимости научиться программировать для них. Новые компьютеры будут все более и более производительными, но программирование не сможет далее развиваться за счет умения «оседлать волну производительности». Основное направление развития параллелизм.
И снова революция, господа! На этот раз «параллельная» - Concurrency Revolution. Мы рады сообщить, что одной из первых революционных программ в области безопасности стала GOALcity Pegal. И забросайте нас шапками! Как бы вы ни критиковали эту статью, даем прогноз, что через пару лет все начнут перестраиваться под все более наращиваемые мощности многопроцессорных систем.
Основные выводы.
1. Что может произойти со стандартной программой, не оптимизированной для работы на многопроцессорных (многоядерных) платформах:
- Второе ядро увеличивает производительность лишь на 30%, хотя вы платите за полный кристалл. Это все равно, что вам не довешивают 70 граммов на каждые 100.
- Каждый следующий процессор может не увеличить, а уменьшить производительность.
- Применение более двух процессоров способно дестабилизировать, а в некоторых случаях полностью парализовать работу программы.
2. По всей видимости, через пару лет сегодняшний софт на старых принципах исполнения кода придется выкинуть.
3. Разработчикам ПО стоит задуматься о параллельном программировании уже вчера, т.к. многопроцессорные системы активно продаются уже сегодня.
4. Параллельное программирование увеличивает мощности компьютерных систем в десятки, а завтра и в сотни раз.
«Большинство многопоточных приложений содержат ошибки, связанные с параллельным исполнением потоков, я считаю, что можно выдвинуть следующую гипотезу – как только многоядерные системы станут широко используемыми, скрытые ошибки в многопоточных программах станут все чаще и чаще проявлять себя, приводя к падению ранее надежных систем. Такой вариант развития событий выглядит особенно удручающим с точки зрения производителей вычислительных систем – следующее поколение ПК будет характеризоваться в сознании потребителя как поколение компьютеров, на которых перестали нормально работать программы, замечательно выполнявшие свои функции на старых компьютерах».
Edward A. Lee.
Electrical Engineering and Computer Sciences University of California at Berkeley
Electrical Engineering and Computer Sciences University of California at Berkeley
Материалs сайта www.goal.ru