Intel® Math Kernel Libraryを導入してFortranから利用する

この記事の概要

Intel® oneAPIという高性能な数値計算ツールキットがある。 以前は結構な値段だったらしいが、昨年あたりから無料で使えるようになった (Intel® oneAPI FAQ)。

oneAPIにはプロファイラーとか深層学習とか色々便利なツールが含まれている。そのうちの一つのMath Kernel Library(mkl)は、LAPACK95やFFTなど高速な数値計算処理を提供する。 LAPACK95のようなライブラリを自力でダウンロード・ビルド・リンクまでするのはかなり手間だが、これからはoneAPIで一括でもってこられる。

そういうわけでこの記事では、oneAPIのインストール手順を紹介し、使用例としてIntel® Fortran Compiler(ifort) からIntel® Math Kernel Libraryの手続きを呼び出して実行する方法を説明する。

Intel® oneAPI Toolkit のインストール

私はUbuntu上にインストールしたので以下のコマンドで。

おおむね公式ドキュメント( APT - Intel® oneAPI Toolkits Installation Guide for Linux* OS ) の通り。

wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB \
| gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null

echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list

sudo apt update

# basekitにはMath Kernel Libraryが含まれる
sudo apt install intel-basekit

# hpckitにはFortran Compilerが含まれる
sudo apt install intel-hpckit

# 環境変数の設定はsetvars.shがよしなにやってくれる
echo "source /opt/intel/oneapi/setvars.sh" >> zsh.rc

最後の行について、setvars.shをShellの起動時に毎回実行させると結構起動がおそくなるので、 alias activate-oneapi="source /opt/intel/oneapi/setvars.sh"などとしてもいいかもしれない。

インストールが完了したことの確認。

$ ifort --version
ifort (IFORT) 2021.5.0 20211109
Copyright (C) 1985-2021 Intel Corporation.  All rights reserved.

$ mkl_help
oneAPI MKL vars.sh Syntax:
    ...

線型方程式系を解く

mklに含まれるlapack95を使って線型方程式系を解いてみる。

コード

! solve_linear_equation.f90
program main
    use lapack95, only: getrf, getrs

    implicit none

    integer, parameter :: N = 3
    integer :: i
    integer :: ipiv(N) ! pivot indices
    real :: a(N,N) ! matrix A
    real :: b(N) ! vector b

    a(:, :) = reshape( &
        [2., -1., 1., 1., 1., 2., 1., -1., 3.], &
        [3, 3] &
    )

    b(:) = [2, 3, -10]

    print *, "A:"
    do i=1, N
        print '(3f6.2)', a(i, :)
    end do

    print *, "b:"
    print '(3f6.2)', b(:)

    ! LU factorization
    call getrf(a, ipiv)
    ! solve linear equations with an LU-factored matrix
    call getrs(a, ipiv, b)

    print *, "x:"
    print '(3f6.2)', b(:)
end program main

各手続の取説はこの辺を見ると良いgetrs - Developer Reference for Intel® oneAPI Math Kernel Library - Fortran

lapack95の手続は総称名になっていて、 例えばgetrfは引数が単精度ならsgetrfに、 倍精度ならdgetrfに勝手にリダイレクトしてくれるので型を気にせず使える。 また、純粋手続になっているのでpure functionの中でも使える。 総じて非常に取り回しが良い。

Ref: Intel® MKL Fortran 95 Interfaces for LAPACK Routines vs. Netlib Implementation

コンパイル

# compile
ifort -c solve_linear_equations.f90 -c -qmkl
# link
ifort solve_linear_equations.o -lmkl_lapack95_lp64 -qmkl

-qmklオプションを付けることでコンパイラが lapack95等のmklモジュールを参照してくれる。

Ref: qmkl, Qmkl - Intel® oneAPI DPC++/C++ Compiler Developer Guide and Reference

が、どうやらモジュールはライブラリの実体を含んでおらず インターフェイスを提供するのみのようで、リンク時には 使用するモジュールに合わせて-lmkl_lapack95_lp64のようにリンクさせてやる必要がある。

結果

$ ./a.out
 A:
  2.00  1.00  1.00
 -1.00  1.00 -1.00
  1.00  2.00  3.00
 b:
  2.00  3.00-10.00
 x:
  3.00  1.00 -5.00

尚、MacOSでは実行時にDYLD_LIBRARY_PATHの指定が必要だった。

export DYLD_LIBRARY_PATH="${DYLD_LIBRARY_PATH}:/opt/intel/oneapi/mkl/latest/lib"