Раньше я был уверен, что, возможно, самая крутая в мире :) математическая библиотека Intel MKL – полностью коммерческая и с чистой совестью пользоваться ей можно только купив лицензию у Intel. Однако, разбираясь со свободными (совершенно бесплатными) системами для научных вычислений, я обнаружил, что Intel MKL входит в состав некоторых из них и используется там как основной решатель для СЛАУ, а также других задач. Как минимум, она входит:
в библиотеки NumPy и SciPy в составе дистрибутива Anaconda Python;
в SciLAB (известная MatLAB-подобная свободная система компьютерной математики).
Пойдя на сайт Intel, я увидел, что и оттуда можно скачать MKL совершенно бесплатно. Скачав, я открыл прилагающийся файл о лицензии и прочитал:
Intel License for Intel® Math Kernel Library and Installer Program (version January 2017). Copyright (c) 2017 Intel Corporation.
Use and Redistribution. You may use and redistribute the software (the “Software”), without modification, provided the following conditions are met:
- Redistributions must reproduce the above copyright notice and the following terms of use in the Software and in the documentation and/or other materials provided with the distribution.
- Neither the name of Intel nor the names of its suppliers may be used to endorse or promote products derived from this Software without specific prior written permission.
- No reverse engineering, decompilation, or disassembly of this Software is permitted.
. . .
Я не юрист, но из этого по-моему следует, что я имею полное право пользоваться MKL и даже ее распространять, если уведомлю в документации на свою программу, что копирайт MKL принадлежит Intel.
Видимо, разработчики Anaconda Python и SciLAB так и делают.
Конечно, если действительно на MKL придется завязать какие-то коммерческие проекты, этот вопрос потребует более глубокого юридического изучения. Для меня подобные юридические вопросы – полные дебри. Тут должны разбираться специальные люди. Но надеюсь, что простое экспериментирование с MKL, так же как и расчеты в NumPy и SciLAB, прав Intel не нарушают. :)
Мои «околонаучные» проекты в основном сделаны в GFortran. А Intel MKL для Windows, к сожалению, тесно интегрирована только с Intel Fortran, который уже точно коммерческий и весьма недешевый. (Под Linux MKL официально работает в том числе и с компиляторами GCC).
Подключить Intel MKL к GFortran в Windows на первый взгляд казалось нетривиальной задачей, но, после определенного разбирательства, это у меня получилось. Как – хочу зафиксировать ниже. Если потом все-таки окажется, что юридически это делать нельзя :), Intel MKL всегда можно заменить на OpenBLAS. Как он подключается – тоже запишу здесь для удобства. (Сказанное относится к библиотекам LAPACK и BLAS – больше мне из MKL пока не нужно).
Intel MKL в GFortrаn
Дистрибутив Intel MKL содержит скомпилированные библиотеки .dll
, а также библиотеки .lib
для компиляции и линковки в Intel Fortran и среде MS Visual Studio.
Мы не используем Visual Studio, а работаем с GFortrаn в составе компиляторов GCC. В принципе, GCC работает и с библиотеками .lib
. Однако, корректно подключить все нужные для компиляции MKL .lib
к GFortrаn – не получается. Судя по форумам, не у меня одного. Поэтому, чтобы вызывать из нашей программы MKL, попробуем подготовить библиотеки в родном для GCC формате .a
и ограничимся динамическим связыванием. В принципе, .a
содержит дистрибутив Intel MKL для Linux (я не поленился, установил MKL в Ubuntu), но .a
в Ликунсе и в Виндовсе – несовместимы.
Нам надо получить из .dll
и .lib
библиотеки .a
. Это возможно. Оказалось, что проще не использовать для этого .lib
вообще. Библиотеки .a
можно сделать просто из *.dll
. Правда, это будут библиотеки только для динамической компоновки. Т.е. чтобы наша программа работала, в системе должно иметься несколько *.dll
с Intel MKL. Кстати, если у нас инсталлирована, например, Anaconda Python, то все необходимые *.dll
библиотеки с ней уже установлены.
Итак, у нас есть ряд .dll
с Intel MKL. Их можно взять как из Anaconda Python, так и из официального дистрибутива Intel MKL, скачанного с их сайта. Первое, по-моему, даже проще т.к. на сайте Intel нужна регистрация.
Оказалось, что нужные нам функции LAPACK и BLAS в привычном формате вызова содержатся конкретно в файле mkl_rt.dll
. Чтобы посмотреть, какие функции входят в *.dll
есть разные утилиты. Проще всего воспользоваться утилитой dumpbin.exe
из состава Visual Studio:
dumpbin /exports mkl_rt.dll
Она выдает следующее:
Ниже по списку упоминаются привычные функции LAPACK dgesv
, dposv
и другие.
Чтобы сделать библиотеку *.a
из *.dll
сначала надо сформировать текстовый файл .def
со списком названий функций, т.е. из того, что обведено красным. В начале этого файла надо написать слово EXPORTS
. Т.е. файл .def
должен выглядеть так:
EXPORTS
CAXPBY
CAXPY
CAXPYI
CAXPY_DIRECT
CBBCSD
CBDSQR
CCOPY
CDOTC
CDOTCI
CDOTU
...
Файл .def
можно сформировать из того, что вывел dumpbin.exe
руками, а можно сделать скрипт, например, на питоне (привожу его ниже).
Получив .def
, осталось сформировать библиотеку *.a
(она должна иметь префикс lib
и суффикс .dll
) с помощью утилиты dlltool.exe
из состава GCC:
dlltool -d mkl_rt.def -D mkl_rt.dll -l libmkl_rt.dll.a
Вот скрипт на Питоне, который делает все описанное. Чтобы он работал в системе должны быть доступны dumpbin.exe
и dlltool.exe
. Кстати, чтобы это проверить, в Windows можно набрать where dumpbin
– система выведет путь, где он лежит, либо скажет, что не находит такого.
DllFile = "mkl_rt.dll" # *.dll-файл, из которого будет сделан *.a-файл
import os
(FileBaseName, FileExt) = os.path.splitext(DllFile)
TmpFile = FileBaseName + ".tmp"
DefFile = FileBaseName + ".def"
AFile = "lib" + FileBaseName + ".dll.a"
os.system("dumpbin /exports " + DllFile + " > " + TmpFile)
LineNo = 1
FirstLineNo = 0
LastLineNo = 0
TmpFile_ = open(TmpFile, 'r')
DefFile_ = open(DefFile, 'w')
DefFile_.write("EXPORTS\n")
for Line in TmpFile_:
if Line.find('ordinal hint') >= 0:
FirstLineNo = LineNo
if Line.find('Summary') >= 0:
LastLineNo = LineNo
if FirstLineNo != 0 and LineNo > FirstLineNo and \
(LastLineNo == 0 or LineNo < LastLineNo):
DefFile_.write(Line[26:]) # Названия функций – начиная с 26 символа
LineNo += 1
TmpFile_.close()
DefFile_.close()
os.system("dlltool -d" + DefFile + " -D " + DllFile + " -l " + AFile)
os.system("DEL *.tmp")
Полученный файл *.a
надо положить туда, где GCC хранит свои библиотеки, либо в папку с нашими собственными библиотеками, например, C:\gcc\mylibs
.
В принципе, это все. Проверим как все работает.
Протестируем MKL на примере из прошлого поста с тестом решения СЛАУ.
Тестовая программа на Фортране (в скоростном варианте с \(LL^T\)-разложением) выглядит так (файл LinTest.f90
):
program LinTest
implicit none
integer, parameter :: n = 1000 ! Число уравнений
integer, parameter :: m = 100 ! Число шагов
real(8), dimension(n,n) :: A, A0 ! Матрица коэффициентов
real(8), dimension(n) :: B ! Вектор правых частей / результатов
real(8) :: s ! Контрольная сумма
integer :: i, j, k ! Вспомог. индексы
integer :: info ! Инфо об успешности решения
integer :: t_0, t_1, t_rate, t_max ! Для измер. времени
!------------------------------------------------------------------------
forall(i=1:n, j=1:n) A0(i,j) = 1-(dble(i-j)/n)**2
forall(i=1:n, j=1:n, i==j) A0(i,j) = 10.
s = 0.
call system_clock(t_0, t_rate, t_max)
do k = 1, m
A=A0
B=k
call dposv("L", n, 1, A, n, B, n, info) ! Вызов процедуры LAPACK
if (info/=0) stop ("Ошибка")
s = s + sum(B)
enddo
call system_clock(t_1, t_rate, t_max)
print *, "Время:", real(t_1-t_0)/t_rate
print *, "Сумма:", s
endprogram
Условно статическая компиляция (пусть наша библиотека libmkl_rt.dll.a
лежит в C:\gcc\mylibs
):
gfortran LinTest.f90 -static -L C:\gcc\mylibs -lmkl_rt.dll -O2 -o LinTest.exe
Запуская программу, получаем:
LinTest.exe
Время: 0.328000009
Сумма: 22439.195088956156
Время 0,33 с – точно такое же как и у лидера прошлого теста Intel Fortran + MKL
.
Размер LinTest.exe
получился 595 КБ (компилятор был из GCC 6.3.0 из дистрибутива MinGW64). В него статически прилинковались все библиотеки, кроме .dll
-библиотек MKL.
Какие в принципе .dll
нужны для работы нашей программы? Если мы хотим, чтобы наша программа работала на другой машине, не имеющей установленную Анаконду или другой вариант MKL, надо будет скопировать и обеспечить доступность 5-ти файлов:
Размер Файл
----------------------------------
1 328 896 libiomp5md.dll
37 854 480 mkl_avx2.dll
25 122 064 mkl_core.dll
24 297 744 mkl_intel_thread.dll
12 629 264 mkl_rt.dll
----------------------------------
101 232 448 байт
100 МБ – конечно, не мало. Это вариант с последним дистрибутивом MLK с сайта Intel, версия 2017.2.187. Из дистрибутива Анаконды набегает поменьше – «всего» 86 МБ. Современный софт, он такой. :)
Полностью динамическая компиляция (убираем ключ -static
):
gfortran LinTest.f90 -L C:\gcc\mylibs -lmkl_rt.dll -O2 -o LinTest.exe
LinTest.exe
получился крошечный – 57 КБ, но теперь для работы потребуются еще три .dll
из GCC (данные для версии 6.3.0):
Размер Файл
----------------------------------
75 264 libgcc_s_seh-1.dll
1 277 952 libgfortran-3.dll
325 632 libquadmath-0.dll
----------------------------------
1 678 848 байт
OpenBLAS в GFortrаn
Установить OpenBLAS – куда проще.
Скачиваем с официального сайта уже скомпилированные бинарные файлы в архиве OpenBLAS-v0.2.19-Win64-int32.zip
(версия для 64-разрядных машин).
Переписываем файлы libopenblas.a
и libopenblas.dll.a
туда, где GCC хранит свои библиотеки, либо в папку с нашими собственными библиотеками, например, C:\gcc\mylibs
.
Статическая компиляция (пусть наши библиотеки *.a
лежат в C:\gcc\mylibs
):
gfortran LinTest.f90 -static -L C:\gcc\mylibs -lopenblas -O2 -o LinTest.exe
Запускаем:
LinTest.exe
Время: 0.483999997
Сумма: 22439.195088956145
Время на 48% больше, чем с Intel Fortran + MKL
, но на самом деле тоже очень достойное.
Размер файла LinTest.exe
, правда, громадный: 26 МБ.
Динамическая компиляция (убираем -static
и добавляем к -lopenblas
суффикс .dll
):
gfortran LinTest.f90 -L C:\gcc\mylibs -lopenblas.dll -O2 -o LinTest.exe
Размер LinTest.exe
– всего 57 КБ. Для работы потребуется libopenblas.dll
из дистрибутива OpenBLAS и еще три DLL из GCC. Общий расклад (данные для версии 6.3.0):
Размер Файл
----------------------------------
75 264 libgcc_s_seh-1.dll
1 277 952 libgfortran-3.dll
42 587 753 libopenblas.dll
325 632 libquadmath-0.dll
----------------------------------
44 266 601 байт
«Всего» 44 МБ – не так и страшно. :)
Комментариев нет:
Отправить комментарий