объекта на конкретную задачу. Объекты предметной области в разных подсистемах корпоративной информационной системы представляются по-разному. При использовании объектно-ориентированного подхода проблема конкретизации объекта решается посредством наследования. Субъектно-ориентированный подход предполагает создание индивидуальных проекций объекта на подсистемы. Таким образом, подсистемы будут манипулировать не самими объектами, а их индивидуальными проекциями, т. е. субъектами. Причем подсистемы должны манипулировать субъектами так, как если бы они являлись полноценными объектами, что позволит вести прикладную разработку, используя традиционные объектно-ориентированные технологии.
Использование субъектов осложняется проблемой их получения из хранилища. В качестве хранилища выступает реляционная база данных. Объектное приложение взаимодействует с реляционной базой данных посредством системы объектно-реляционного отображения (ОИМ-системы). Готовых систем субъектно-реляционного отображения не существует. Следовательно, необходимо построить эффективный метод получения субъектов.
Проблему можно решить несколькими путями.
Первый способ решения заключается в получении субъектов средствами самого хранилища (например, при помощи SQL-запросов). Однако данное решение является зависимым от конкретной системы управления базами данных.
Второй способ решения заключается в хранении в базе данных не только объектов, но и субъектов. Однако этот подход значительно усложняет схему базы данных.
Третий способ решения заключается в использовании субъектной надстройки над объектной моделью предметной области. Этот путь является наиболее простым в реализации, и именно он выбран для решения проблемы получения субъектов при создании корпоративной информационной системы вуза.
При построении субъектной надстройки над объектной моделью предметной области используется многослойная архитектура. Каждый слой выполняет определенные функции. Целью расслоения является максимально возможное уменьшение нагрузки на каждый слой, что позволяет не смешивать бизнес-логику с процедурами обращения к хранилищу данных.
Нижний слой оперирует непосредственно пер-систентными объектами, возвращаемыми ORM-сис-темой. Следующие слои инкапсулируют эти персис-тентные объекты и собирают из них индивидуальные проекции. Инкапсуляция персистентных объектов дает возможность разработчику свести к минимуму зависимость кода от конкретной ORM-системы.
Рассмотренная технология поддержки субъектов позволяет вести разработку корпоративной информационной системы вуза естественным образом, автоматизируя каждое структурное подразделение максимально независимо друг от друга.
список литературы
1. Sun Microsystems. Россия и СНГ. Java 2 Enterprise Edition. http:// ru.sun.com/java/j2ee /index.html.
2. Microsoft Россия. Visual Studio .NET. http://msdn. microsoft.com/library/rus/.
3. Subject-oriented programming. http://www.research.ibm. com/sop/.
УДК 004.383.5:519.612
решение систем линейных алгебраических уравнений на графических процессорах с использованием технологии cuda
н. о. МАТВЕЕВА, В. И. ГОРБАЧЕНКО Пензенский государственный педагогический университет имени В. Г. Белинского кафедра вычислительных систем и моделирования
Рассматривается технология программирования графических процессоров CUDA (Compute Unified Device Architecture) фирмы NVIDIA. Предлагаются алгоритмы распараллеливания решения больших систем линейных алгебраических уравнений методом бисопряженных градиентов с использованием технологии CUDA. Эксперименты показали, что для систем большого порядка время решения с использованием CUDA сокращается более чем на порядок по сравнению с решением только на центральном процессоре.
ТЕХНОЛОГИЯ ПРОГРАММИРОВАНИЯ НА ГРАФИЧЕСКИХ ПРОЦЕССОРАХ Уже в течение нескольких лет графические процессоры (GPU) используются для неграфических вычислений. Это связано с тем, что видеокарты состоят из множества мультипроцессоров, которые управляют высокоскоростной памятью, что делает их использование эффективным как для графических, так и для не графических вычислений.
GPU специально приспособлен для решения задач, которые могут содержать параллельные вычисления с достаточно большим отношением числа арифметических инструкций к числу обращений к памяти [8]. Так как выполняется большое количество арифметических операций и небольшое количество обращений к памяти, время доступа к памяти может быть совмещено с расчетами, вместо большого кэширования данных. Параллельные вычисления элементов данных осуществляется за счет параллельно выполняемых
потоков. Многие приложения, которые вычисляют большие объемы данных, представленные массивами, могут использовать параллельную программную модель для ускорения вычислений.
Однако до недавнего времени доступ ко всем вычислительным мощностям видеокарт и эффективное использование их для неграфических вычислений оставался сложным, в связи с возможностью управления GPU только через графические API. Но в 2007 году для эффективной поддержки неграфических приложений для чипов NVIDIA была создана технология программирования - "CUDA" (Compute Unified Device Architecture) - унифицированная вычислительная архитектура для различных задач, содержащая специальный SDK, API и компилятор языка С, обеспечивающие быструю разработку и адаптацию программ для исполнения на GPU. CUDA предназначена для работы на новом поколении GPU NVIDIA от G80 и выше [1, 8].
Программное обеспечение CUDA состоит из нескольких уровней [8]: драйвер устройства, программный интерфейс (API), высший уровень - две математические библиотеки CUFFT [7] (библиотека для
быстрого преобразования Фурье) и CUBLAS [6] (библиотека содержащая основные операции линейной алгебры). CUDA API является расширением языка С, что позволяет разработчикам не тратить много времени на изучение данной технологии.
Когда используется технология CUDA, графический процессор (device) действует как сопроцессор к главному процессору (host). Другими словами, часть приложения, отличающаяся параллелизмом данных, выполняется на видеокарте. Более точно, часть приложения, которая выполняется много раз, но независимо над различными данными, может быть выделена в функцию, которая выполняется на GPU как множество различных потоков. Такая функция называется ядром (kernel). Ядро выполняется над сеткой (grid), представляющей собой одно- или двумерный массив блоков (block) (рис. 1). Блоки же в свою очередь объединяют определенное количество потоков (thread), которые могут между собой взаимодействовать через разделяемую память и точки синхронизации. Блок может выполняться только на одном мультипроцессоре, но на одном мультипроцессоре может выполняться несколько блоков.
Рисунок 1. Группирование потоков
И хост и устройство поддерживают свою собственную динамическую память. Одна память может копировать данные из другой с помощью оптимизированных АР1-запросов, которые используют высокоп-
роизводительные механизмы управления доступом к памяти. каждый поток имеет доступ к следующим видам памяти (рис. 2): регистры (registers) и локальная память (local memory) (чтение-запись внутри потока);
разделяемая память (shared memory) (чтение-запись внутри блока); глобальная память (global memory) (чтение-запись внутри сетки); постоянная память (constant memory) и текстурная память (texture memory) (только чтение внутри сетки). CUD А обеспечивает адресацию общей динамической памяти, и это дает возможность чтения и записи данных независимо от их местополо-
АР1 технологии CUDA включает в себя: набор средств, позволяющих программистам выделять часть кода, выполняющегося на GPU; главный компонент, который запускается на хосте и обеспечивает функции контроля и доступа к другим вычислительным устройством хоста; компонент устройства, который выполняется на видеокарте и обеспечивает функции, специфичные для данного устройства; общий компонент, который обеспечивает встроенные переменные векторного типа и общее подмножество стандартной библиотеки С, которое поддерживается и хостом и устройством.
Для возможности отладки программ в CUDA предусмотрен режим эмуляции, когда приложение полностью выполняется на центральном процессоре (CPU), и каждый поток GPU эмулируется потоком CPU. При работе в режиме эмуляции можно пользоваться привычными средствами отладки, что позволяет быстрее находить ошибки в программе.
жения в динамической памяти. CUDA имеет кэш и разделяемую память с очень быстрым параллельным чтением разделяемых данных и доступом на запись. Приложения могут использовать это преимущество для минимизации затрат на перемещение данных между процессорами и динамической памятью, делаясь менее зависимыми от объема динамической памяти.
АЛГОРИТМЫ РЕШЕНИЯ СИСТЕМ АЛГЕБРАИЧЕСКИХ УРАВНЕНИЙ НА ВИДЕОКАРТАХ До настоящего времени (более 20 лет) архитектура предшествующих поколений GPU базировалась на традиционном графическом конвейере, который состоял из последовательных этапов обработки потока графических данных [1]. Первые поколения GPU имели жесткую структуру, ограниченную функциональность и были не программируемыми. Современные GPU содержат полностью программируемые параллельные процессоры с полным и мощным набором команд для выполнения арифметических и логических операций с поддержкой 32-битного формата векторных и скалярных операций с плавающей точкой. Для быстрой обработки больших графических наборов данных используют потоковую модель обработки с параллелизмом. В связи с этим GPU стали привлекательными для реализации неграфических вычислений.
Непрерывное совершенствование возможностей видеокарт, стимулируемое потребностями любителей
Grid
Block (0, 0) Block (1, 0)
Shared Memory Shared Memory
L L I L
Registers Registers Registers Registers
f r ! r Г
Thread {0, 0) Thread (1, 0] Thread (0, 0) Thread (1, 0)
t ' J à t ' L i J t ' L i à i i L
Local Memory Local Memory Loca 1 Memory Local Memory
1 1 1 F
Global Memory
Constant Memory
Texture Memory
Рисунок 2. Модель памяти
компьютерных игр, привело к тому, что современные графические процессоры сложные математические задачи решают на порядок быстрее центральных процессоров. Основная причина этого в том, что видеокарты специализируются на больших объемах вычислений, что является основой построения графического изображения, и из-за этого архитектура графического процессора опирается на векторный принцип обработки данных.
Решение больших систем линейных алгебраических уравнений (СЛАУ) принадлежит к кругу задач, для которых применение новейшей высокопроизводительной вычислительной техники дает максимальную выгоду [4]. Алгоритмы решения систем уравнений допускают возможность эффективного распараллеливания вычислений. В связи со спецификой задачи наиболее логично использовать векторные методы решения. Суть данных методов распараллеливания заключается в выполнении одной и той же операции над различными элементами данных. Такой способ ускорений вычислений свойственен графическим процессорам (GPU).
Как известно, алгоритмы решения СЛАУ делятся на прямые и итерационные [2-5]. На сегодняшний день не существует библиотек, реализующих методы решения систем уравнений на графическом процессоре. Одним из самых эффективных итерационных алгоритмов является метод бисопряженных градиентов для систем с несимметричной матрицей [3]. Ниже приводится основной алгоритм (рис. 3), в котором используется скалярное произведение (x,y) = xTy , а через гу = b - Axу обозначается невязка на j-том шаге. Операцию вида a + a b, где a и b - векторы, а а - скаляр, будем называть триадой.
Выбрать начальное приближение х0 г0 = Ь - Ахо
Выбрать вектор Г0, удовлетворяющий условию (г0, Г0) Ф 0
Ро = Г0> Р 0 = Г0 Вычислить (г0, Г0)
Для у = 0,1,...
а у = (гу, Гу )/(АР у, Р у )
Х+1 = х у + а Ру
у = г - а АРу
j+1 rJ+1
r j+1 = f - а A p
в у = ^у^ Гу + 1)/(Гу , Гу )
Если ||г,+^ < е , то КОНЕЦ (решение достигнуто)
Если в у = 0, то КОНЕЦ(при данном Г0 метод не сходится)
Ру+1 = Гу + вуРу
Ру+1 = Гу + вуРу увеличить
Рисунок 3. Алгоритм метода бисопряженных градиентов
Рассматриваемый метод базируется в основном на операциях вычисления скалярного произведения и матрично-векторных умножениях вида Ap . В частности, полные вычислительные потребности одной итерации алгоритма метода бисопряженных градиентов можно обрисовать следующим образом:
- Apj, одно скалярное произведение ((гу,Гу) уже известно), одно деление;
- одна триада;
- одна триада ( Ap j уже известно);
- ATpу , одна триада;
- одно скалярное произведение, одно деление ( (fy., fy.) уже известно);
- одно скалярное произведение, два сравнения;
- одна триада;
- одна триада.
Таким образом, общая потребность в вычислениях на одну итерацию составляет: вычисление Ap и ATpу , три скалярных произведения, пять триад, два деления и два сравнения.
Для любой серьезной задачи в вычислительных затратах метода бисопряженных градиентов будет доминировать вычисление произведений Ap и ATpу и поэтому эффективная реализация операции умножения матрицы на вектор является ключевым моментом.
Умножение полной матрицы A размером n х n на вектор p состоит из n скалярных произведений
n
строк матрицы на вектор xt = ^ ауРу. Такая опера-
у=1
ция является легко распараллеливаемой, так как вычисление одного элемента результирующего вектора не зависит от вычислений других элементов. Следовательно, исходя из структуры современных GPU, которые состоят из набора мультипроцессоров, каждое скалярное произведение A;p , где A; строка матрицы A , можно выполнять на отдельном мультипроцессоре. для этого матрица разбивается на блоки, один блок содержит одну строку Ai и вычисляет один элемент результирующего вектора.
Но этим распараллеливание еще не ограничивается, так как каждый мультипроцессор состоит из определенного числа процессоров, имеющих общую разделяемую высокоскоростную память, что позволяет распараллелить вычисление скалярного произведения. В каждом блоке создаем по m = 2z потоков, количество потоков ограничено максимально возможным числом потоков в блоке. Поток j читает из глобальной памяти у -ые, у + m -ые, ... компоненты вектора p и строки матрицы A;, вычисляет соответствующие произведения и записывает их в разделяемую память. Потоки выполняются параллельно. далее первая половина потоков параллельно производит сложение
sk + sk+m/2, 0 ^ k < m /2, sk - k -я ячейка разделяемой памяти (рис. 4). Затем аналогичные действия выполняются m /4 потоками, и т.д. до получения в s0 вычисляемого скалярного произведения.
Вычисление одного скалярного произведения на векторном устройстве не дает ускорения по сравнению с последовательным вычислением на центральном процессоре, однако при параллельном вычислении нескольких скалярных произведений эффективность возрастает пропорционально количеству произведений. Из этого следует, что описанный способ умножения матрицы на вектор на графическом процессоре дает большее ускорение при увеличении размерности матрицы.
Еще одна операция, используемая в методе би-сопряженных градиентов, триада, выполняется на
векторных устройствах эффективно, так как каждый компонент результирующего вектора вычисляется независимо от других и не возникает конфликтов при обращении к памяти. Но время, затрачиваемое на триады, составляет незначительную часть от времени всех вычислений.
Таким образом, ключевым моментом реализации метода бисопряженных градиентов на видеокарте является процедура матрично-векторного умножения. Однако необходимость вычисления отдельных скалярных произведений проводит к некоторому понижению общей эффективности.
Рисунок 4. Вычисление скалярного произведения на GPU
АНАЛИЗ РЕЗУЛЬТАТОВ Основываясь на рассмотренных алгоритмах распараллеливания, метод бисопряженных градиентов для решения СЛАУ был реализован с использованием описанной технологии CUDA. В результате реализации алгоритма, было получено значительное ускорение вычислений по сравнению
с аналогичной реализацией на центральном процессоре. Было проведено сравнение времени решения СЛАУ на видеокарте nVIDIA GeForce 8800 GTX и на центральном процессоре Intel Pentium 4 3.00GHz. Графики зависимости времени получения решения от размерности матриц представлены на рисунке 5.
25
к 20
15
S 10
■ графический процессор Центральный процессор
t / /
/ / i /............
4 * .......ii....... *
#4
500
1000
1500
2000
2500
размерность матрицы
Рисунок 5. Графики зависимости времени решения от размера СЛАУ
Новая технология CUDA для вычислений на графических процессорах является удобным средством эффективного использования вычислительных возможностей видеокарт нового поколения, как для графических, так и для неграфических вычислений. CUDA улучшает существующую модель программирования GPU за счет введения быстрой разделяемой памяти и возможности синхронизации потоков.
Современные видеокарты имеют большие возможности эффективного распараллеливания векторных операций, что позволяет значительно ускорить получение решения систем линейных уравнений больших размеров. например, методом бисопряженных градиентов система линейных уравнений с матрицей размера 2048х2048 решается на графическом процессоре приблизительно в 11 раз быстрее, чем на центральном процессоре.
список ЛИТЕРАТУРЫ
1. Аляутдинов М. А., Троепольская Г. В. Использование современных многоядерных процессоров в нейроком-
пьютерах для решения задач математической физики // Нейрокомпьютеры: разработка, применение. 2007. № 9. С. 71-80.
2. Амосов А. А., Дубинский Ю. А., Копченова Н. В. Вычислительные методы для инженеров. М.: Издательство МЭИ, 2003. 596 с.
3. Баландин М. Ю., Шурина Э. П. Методы решения СЛАУ большой размерности. Новосибирск: Изд-во НГТУ, 2000. 70 с.
4. Ортега Дж. Введение в параллельные и векторные методы решения линейных систем. М.: Мир, 1991. 367 с.
5. Формалев В. Ф., Ревизников Д. Л. Численные методы. М.: ФИЗМАТЛИТ, 2004. 400 с.
6. CUDA CUBLAS Library. http://developer.download. nvidia.com/compute/cuda/ 1_1/CUBLAS_Library_ l.l.pdf. 2007.
7. С U DA С UFFT Library. http://developer.download.nvidia. com/compute/cuda/1_1 /CUFFT_Library_1.1. pdf. 2007.
8. NVIDIA CUDA Compute Unified Device Architecture. Programming Guide. http://developer.download.nvidia. com/compute/cuda/1_1 /NVIDIA_CUDA_Programming_ Guide_1.1.pdf. 2007.