ИСТИНА |
Войти в систему Регистрация |
|
ИСТИНА ИНХС РАН |
||
Разработка программного обеспечения для решения задач математической физики долгое время проводилась при неявном предположении о некоторой идеальной «классической» вычислительной системе, в которой вычислительная стоимость каждой операции выражалась некоторым постоянным числом, не зависящим от расположения операндов в памяти и предыстории этой операции. Хотя уже, по крайней мере, в 90-е годы эта гипотеза не была вполне справедлива (cache-память различного уровня, динамическое выполнение), все же она принималась фактически, так как позволяла оценить трудоемкость того или иного алгоритма самого по себе. Между тем, при использовании современных вычислительных систем особенности их конкретной архитектуры (от которых, вообще говоря, хотелось бы абстрагироваться) могут приводить к крайне неэффективному использованию вычислительных мощностей, если их игнорировать. В данной работе рассматриваются результаты низкоуровневой оптимизации одного кода, который был в свое время написан (и разумно оптимизирован) исходя из «классических» представлений о вычислительной системе. Будучи ориентированным на решение по явной схеме систем гиперболических уравнений (в основном, газовой динамики) в двумерных областях сложной формы с использованием неструктурированных сеток, этот код был написан на C++ с очень широким использованием объектно-ориентированного подхода для обеспечения максимальной универсальности и простоты дальнейшего развития. Явный солвер гиперболических систем общего вида был параметризован по физическому наполнению и способу вычисления потоков, а реализация граничных условий и уравнений состояния различного вида осуществлялась через иерархии классов с порожденными функциями. С целью минимизации количества одновременно хранимых вспомогательных величин был использован «фронтальный», или «волновой», алгоритм прохода элементов сетки для вычисления значений на очередном временном слое. В ходе данного исследования был выполнен комплекс преобразований программы, включая: отказ от фронтального алгоритма обхода сетки в пользу однородного обхода всей сетки в произвольном порядке (нет зависимостей и практически нет операторов ветвления); предварительное вычисление «структурных» величин (списки смежности сеточных элементов и т.п.); исключение тяжелых операций (динамическое выделение памяти, создание или удаление множеств и других структур данных) в вычислительно-емких циклах; использование обычных массивов для хранения всех величин; переход от массивов структур к массивам отдельных величин; развиртуализцию вызовов. Эти преобразования привели: к многократному (25 раз) ускорению исходной последовательной программы; возможности тривиального распараллеливания ее в модели OpenMP; возможности беспроблемного портирования на ГПУ (в модели DVMH получено ускорение около 450 раз относительно исходной версии на 1 ГПУ); перспективе распараллеливания на кластер с ГПУ в расширенной модели DVMH.