読者です 読者をやめる 読者になる 読者になる

OpenBLAS 0.2.13 のビルド

コンパイラの確認

% gcc --version
gcc (Debian 4.7.2-5) 4.7.2
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Intel や PGI コンパイラでは駄目らしい (https://github.com/xianyi/OpenBLAS/blob/develop/Makefile.rule line 21).

CPUの確認

% grep 'model name' /proc/cpuinfo | head -n 1
model name      : Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz

Ivy Bridge だが,ビルドの際は Sandy Bridge を指定する (後述).

ソースのダウンロード

OpenBLAS : An optimized BLAS library から tarball をダウンロードし,解凍する.

% cd /tmp
% wget http://github.com/xianyi/OpenBLAS/tarball/v0.2.13
% tar zxf v0.2.13
% cd xianyi-OpenBLAS-aceee4e

または xianyi/OpenBLAS · GitHub から clone する.

% cd /tmp
% git clone git://github.com/xianyi/OpenBLAS
% cd OpenBLAS

ビルド

% make TARGET=SANDYBRIDGE BINARY=64 USE_OPENMP=1 INTERFACE64=1 \
  2>&1 | tee make-all.log
% su
# make install PREFIX=/usr/local/openblas-0.2.13_gcc-4.7.2 \
  2>&1 | tee make-install.log
  • make の際の変数は上記のように指定するか ./Makefile.rule の対応する変数を編集する
  • コンパイラ等の設定は上記にあるので参照すること
  • TARGET の一覧は ./TargetList.txt にある (何もしなくても自動で検出してくれるらしい)

環境変数の設定

$HOME/.zshrc に以下を追加する.

# OpenBLAS 0.2.13
export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/openblas-0.2.13_gcc-4.7.2/lib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/openblas-0.2.13_gcc-4.7.2/lib
export C_INCLUDE_PATH=$C_INCLUDE_PATH:/usr/local/openblas-0.2.13_gcc-4.7.2/include
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/local/openblas-0.2.13_gcc-4.7.2/include

テスト

以下に示す test_cblas.c を作成する.

//! @file test_cblas.c
#include <stdio.h>
#include <cblas.h>
#define M 3
#define N 3
#define K 2

//! cblas_ddot
void Level1()
{
    printf("%s: %s\n", __func__, "cblas_ddot");

    double x[N] = {1.0, 1.0, 1.0};
    double y[N] = {1.0, 2.0, 3.0};

    // x^T y
    double dot_product = cblas_ddot(N, x, 1, y, 1);

    printf("%.1f\n", dot_product);
}

//! cblas_dgemv
void Level2()
{
    printf("%s: %s\n", __func__, "cblas_dgemv");

    double A[M*K] = {1.0, 2.0,
                     3.0, 4.0,
                     5.0, 6.0};      // M-by-K matrix
    double x[K]   = {1.0, 1.0};
    double y[M]   = {0.0, 0.0, 0.0};

    CBLAS_ORDER     order = CblasRowMajor; // row major
    CBLAS_TRANSPOSE trans = CblasNoTrans;  // not transposed
    int    lda   = K;   // number of rows of A (row major)
    double alpha = 1.0; // coefficient of A x
    double beta  = 0.0; // coefficient of y

    // y = alpha A x + beta y
    cblas_dgemv(order, trans, M, K, alpha, A, lda, x, 1, beta, y, 1);

    for (int i = 0; i < M; i++) printf("%.1f\t", y[i]);
    printf("\n");
}

//! cblas_dgemm
void Level3()
{
    printf("%s: %s\n", __func__, "cblas_dgemm");

    double A[M*K] = {1.0, 2.0,
                     3.0, 4.0,
                     5.0, 6.0};      // M-by-K matrix
    double B[K*N] = {1.0, 2.0, 3.0,
                     4.0, 5.0, 6.0}; // K-by-N matrix
    double C[M*N] = {0.0, 0.0, 0.0,
                     0.0, 0.0, 0.0,
                     0.0, 0.0, 0.0}; // M-by-N matrix

    CBLAS_ORDER     Order  = CblasRowMajor; // row major
    CBLAS_TRANSPOSE TransA = CblasNoTrans;  // not transposed
    CBLAS_TRANSPOSE TransB = CblasNoTrans;  // not transposed
    int    lda   = K;   // number of rows of A (row major)
    int    ldb   = N;   // number of rows of B (row major)
    int    ldc   = N;   // number of rows of C (row major)
    double alpha = 1.0; // coefficient of A B
    double beta  = 0.0; // coefficient of C

    // C = alpha A B + beta C
    cblas_dgemm(Order, TransA, TransB, M, N, K,
            alpha, A, lda, B, ldb, beta, C, ldc);

    for (int i = 0; i < M; i++)
    {
        for (int j = 0; j < N; j++) printf("%4.1f\t", C[i*N+j]);
        printf("\n");
    }
}

int main()
{
    Level1();
    Level2();
    Level3();
    return 0;
}
% gcc -std=c99 -I/usr/local/openblas-0.2.13_gcc-4.7.2/include \
  -L/usr/local/openblas-0.2.13_gcc-4.7.2/lib \
  -lopenblas -lpthread -lgfortran test_cblas.c
% ./a.out
Level1: cblas_ddot
6.0
Level2: cblas_dgemv
3.0     7.0     11.0
Level3: cblas_dgemm
 9.0    12.0    15.0
19.0    26.0    33.0
29.0    40.0    51.0

なお,CBLAS_ORDERCBLAS_TRANSPOSEopenblas/include/cblas.h に以下のように定義されている.

typedef enum CBLAS_ORDER     {CblasRowMajor=101, CblasColMajor=102} CBLAS_ORDER;
typedef enum CBLAS_TRANSPOSE {CblasNoTrans=111, CblasTrans=112, CblasConjTrans=113, CblasConjNoTrans=114} CBLAS_TRANSPOSE;

環境変数が通っていれば -I および -L オプションは不要.

BLAS Level 1

cblas_ddot が計算するのは $$ \text{dot} \gets {\it \boldsymbol{x}} \cdot {\it \boldsymbol{y}} $$ である (double precision dot product).${\it \boldsymbol{x}} = [1, 1, 1] ^ \intercal, {\it \boldsymbol{y}} = [1, 2, 3] ^ \intercal$ なので $$ {\it \boldsymbol{x}} \cdot {\it \boldsymbol{y}} = 6 $$


BLAS Level 2

cblas_dgemv が計算するのは $$ {\it \boldsymbol{y}} \gets \alpha {\it \boldsymbol{A}} {\it \boldsymbol{x}} + \beta {\it \boldsymbol{y}} $$ である (double precision general matrix-vector product). $$ {\it \boldsymbol{A}} = \begin{bmatrix} 1 & 2 \\ 3 & 4 \\ 5 & 6 \end{bmatrix} , \; {\it \boldsymbol{x}} = \begin{bmatrix} 1 \\ 1 \end{bmatrix} , \; {\it \boldsymbol{y}} = \boldsymbol{0} ;\\ \alpha = 1, \; \beta = 0 $$ なので,要するに ${\it \boldsymbol{y}} ={\it \boldsymbol{Ax}}$ である.答えは $$ {\it \boldsymbol{y}} = \begin{bmatrix} 3, & 7, & 11 \end{bmatrix} ^ \intercal $$


BLAS Level 3

cblas_dgemm が計算するのは $$ {\it \boldsymbol{C}} \gets \alpha {\it \boldsymbol{A}} {\it \boldsymbol{B}} + \beta {\it \boldsymbol{C}} $$ である (double precision general matrix-matrix product). $$ {\it \boldsymbol{A}} = \begin{bmatrix} 1 & 2 \\ 3 & 4 \\ 5 & 6 \end{bmatrix} , \; {\it \boldsymbol{B}} = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix} , \; {\it \boldsymbol{C}} = \boldsymbol{O} ;\\ \alpha = 1, \; \beta = 0 $$ なので,要するに ${\it \boldsymbol{C}} ={\it \boldsymbol{AB}}$ である.答えはもちろん $$ {\it \boldsymbol{C}} = \left[ \begin{array}{rrr} 9 & 12 & 15 \\ 19 & 26 & 33 \\ 29 & 40 & 51 \end{array} \right] $$

参考