Что делать, помогите? |
BLAS
Сегодня будет лекция, посвященная разделу BLAS. BLAS — это сокращенно от Basic Liner Algebra Subprograms, то есть подпрограммы для базовых элементов линейной алгебры. Этот стандарт используется в большинстве других библиотек, то есть Blas используется как некие кубики, из которых строятся некие другие библиотеки, в частности LAPACK. Это стандарт де-факто, и первая его версия была принята где-то в 1979 году. С тех пор существует множество реализаций этой библиотеки, на этом сайте http://www.netlib.org/blas можно посмотреть, как эта библиотека развивалась и из чего она состоит.
Выделяют несколько уровней Blas (как у нас в линейной алгебре существуют операции над векторами, операции над матрицами). Здесь тоже делятся таким образом внутри уровня, то есть у нас есть векторные операции, операции вектор на матрицу — это второй уровень, и матричные операции. В первом случае х и у — это вектора, альфа – это константа. Здесь (во втором случае) с помощью А обозначена матрица, то есть с помощью больших букв А, В, С — также матрицы.
Для чего не предназначен MKL, именно Blas в MKL. Вот когда у нас существуют простые операции, типа как у нас в графике: поворот вектора на какой-то небольшой угол, и таких операций очень много, они, как правило, простые: для вращения трехмерных сцен, и матрица 3 на 3, 3 на 4, чтобы еще смасштабировать всю сцену, и так далее. Так вот, MKL Blas'овский не предназначен для работы с вот такими маленькими операциями и векторами. Для этого существует специальная библиотека, называется IPP (Intel Performance Primitives), вот там такие операции реализованы очень эффективно. А если у вас размеры векторов больше десятка, тогда можете использовать Blas. Вот по этой ссылке (3.20) можно прочитать про IPP. На одной из следующих лекций я вам немножко подробнее про него расскажу.
Как я упоминал, существует множество реализаций Blas, и вот некоторые из них представлены здесь (3.40). В частности, мы будем рассматривать MKL'ную реализацию. То есть существует реализация интерфейса для Blas на С на Fortran'е, для Fortran'а 95-го, 97-го.
Что меня всегда несколько удивляло, но, с другой стороны, пускай остается так, как есть, — это именование функций во всех Blas, LAPACK и так далее. В принципе, названия короткие, но за ними много что скрывается. Например, название cdotc. За ним скрывается то, что это произведение двух комплексных векторов, sdot — произведение комплексное двух векторов, состоящих из чисел с одинарной точностью. И вот так все названия функций состоят и некоего префикса, который говорит, с каким типом он работает, имени самой функции и неких модификаторов, которые у этих переменных бывают. В принципе, такие названия, они есть. Их запомнить, наверное, можно только часть, — с которыми работаете. Но, понимая принцип, можно нужную функцию быстро найти.
То есть у нас есть некий символ, дальше – имя, дальше – модификатор и, собственно, сама функция. Символы обозначают: s – это вещественное число в одинарной точности, с – это комплексное число тоже в одинарной точности, d – это "дабл", двойная точность, ну и z – это тоже комплексное число, но двойной точности.
Названий, как правило, тоже есть несколько. Это ?dot – это скалярное произведение векторов, ?rot (от rotation – поворот) – повернуть вектор, ?swap, ?copy — копирование и так далее. И есть различные модификаторы. Это для Blas Level 1 для работы с векторами.
Когда у нас идет работа с матрицами, у нас матрицы могут храниться в различных форматах. И, соответственно, в зависимости от того, какая матрица (либо ленточная, симметричная, упакованный формат и так далее), имя тоже может быть различным.
Самое интересное, если в первом случае имя задает то, что мы делаем с вектором (с операторами), то здесь это задается модификатором. То есть мы можем делать произведение матрицы на вектор, также можем матрицу на матрицу перемножать, решать системы уравнений (с одной правой частью, с несколькими правыми частями) и так далее.
На сайте Intel была обнаружена вот такая картина (см. рис. 7:55), говорящая, что разработанная компанией Intel и оптимизированная под их процессоры MKL, в частности Blas, работает намного шустрее, чем реализация ATLAS. Быстрее как для одного процессора, так и быстрее на восьми процессорах на машине Intel Xeon с тактовой частотой 2,4 ГГц.
Существуют различные расширения Blas: Sparce Blas – это работа с разреженными матрицами и PBlas (Parallels Blas) для работы на кластерах, на системах с распределенной памятью, там уже реализация через MPI.
Собственно, вот это вся общая теоретическая часть, а сейчас хотелось бы показать вам пару примеров, с чем вам придется работать.
В документации к MKL существует MKL маны. В частности, здесь расписаны функции (вполне возможно, вам эту документацию вчера показывали) для Blas первого уровня, второго, третьего и так далее. Довольно подробно расписаны все функции, которые есть . Соответственно, не все функции могут принимать всевозможные типы данных. Вот, например, функция ?asum – это суммирование элементов массива, можем суммировать любые элементы массива: расписан прототип функции для FORTRAN 77, FORTRAN 95 и что подразумевается под каждым из параметров, что эта функция вычисляет. И так для каждой функции, которая есть. Для работы с матрицами – пожалуйста, тоже набор функций и точно также их прототипы. Кроме того, есть общая информация, но ее я вам уже рассказал (о именовании функции, какие модификаторы могут у них быть).
В зависимости от того, где установлен MKL, есть папочка с примерами, где есть очень много примеров по всем темам, которые мы будем проходить. В частности, по Blas есть примеры исходных кодов на различные функции. Например, sdotx – это уже скалярное произведение векторов и чисел с одинарной точностью. Пример несложный, с учетом того, что комментарий большой. Смысл в чем: считываем данные, печатаем исходные вектора, после чего – вызов функции, после чего – печать результата. Все эти примеры вы можете собрать, скомпилировать и посмотреть. Для каждого пример есть набор входных данных, матриц, векторов. Все эти примеры можно скомпилировать, они не только автоматически компилируются, но еще и запускаются с исходными входными данными. Получается сама программа плюс некий выходной файл. В частности, для программы суммы элементов векторов был входной вектор, можно проверить, что результат совпадает.
В частности, хотелось показать, почему рекомендуется (если вы будете работать под Linux), использовать makefile, потому что строка компиляции (если вы прошлую лекцию помните) там не такая короткая получается. Там нужно указать библиотеки, которые подключаются, что вы используете OpenMP, что вы используете еще библиотеку потоков и так далее.
Если вы просто make запустите для тех примеров, которые есть, то вы увидите некую документацию. В документации сказано, что надо указать, что вы собираете под 32-х разрядную платформу и, например, для функции sdot. По умолчанию он будет собирать все. Это то, что он делает, в развернутом виде (16.14). Понятно, что все это вам делать руками не надо, за вас кое-что сделано, кроме того, он каждый раз выполняет одну забавную штуку, которую вам достаточно будет выполнить только один раз. Ну, раз выполняет – почему нет.
То есть это установка перемены окружения, где лежат библиотеки (export LD library Path). Там длинная строчка идет, где он указывает пользовательские библиотеки, свои библиотеки, это пути, где они лежат. Сейчас найдем, где начинается, собственно, компиляция…просто у нас не все влезло на экран, поэтому…вот: ifort – это компилятор, вот строка компиляции…отсюда вот до сюда, где он опять использует кучу путей, указывает, что использует OpenMР, библиотеку thread, куда сохранять файл. После чего опять устанавливает перемены окружения среды, то есть по сути дела дублирует, и вызывает наш файл, передавая ему входные параметры и записывая результат.