鲲鹏社区首页
中文
注册
开发者
我要评分
文档获取效率
文档正确性
内容完整性
文档易理解
在线提单
论坛求助

生成完整的LAPACK

KML_LAPACK依赖于开源的Netlib LAPACK以提供完整的LAPACK接口功能。因此安装KML_LAPACK后需自行获取开源的Netlib LAPACK v3.12.0的源代码包。

操作步骤

  1. 下载Netlib LAPACK v3.12.0的源代码包v3.12.0.tar.gz。解压后保存在编译机器可访问的路径中,假设位于“/data/Download/lapack-3.12.0”,通过以下命令设置环境变量指定Netlib LAPACK源码路径。
    export LAPACK_SRC_DIR=/data/Download/lapack-3.12.0
  2. 假设libklapack.so位于“/usr/local/kml/lib/neon/libklapack.so”,使用以下脚本编译生成功能完整的libklapack_full.so。
    set -eE
    # Some helper functions --------------------------------------------------------
    function INFORM { printf "\n====== $1\n" ; }
    function DIE { printf "\nFATAL ERROR: $*\n" ; exit 1 ; }
    INFORM "Define and check build and test parameters ($0)"
    echo "LIBKLAPACK_SO         ${LIBKLAPACK_SO:=/usr/local/kml/lib/neon/libklapack.so}"
    echo "LIBKBLAS_SO           ${LIBKBLAS_SO:=$(dirname ${LIBKLAPACK_SO})/kblas/multi/libkblas.so}"
    echo "LAPACK_SRC_DIR        ${LAPACK_SRC_DIR:=/undefined/LAPACK_SRC_DIR}"
    echo "BUILD_DIR             ${BUILD_DIR:=${PWD}/tmp-build-lapack}"
    echo "CMAKE_BUILD_TYPE      ${CMAKE_BUILD_TYPE:=Release}"
    echo "CTEST_PARALLEL_LEVEL  ${CTEST_PARALLEL_LEVEL:=8}"
    echo "OMP_NUM_THREADS       ${OMP_NUM_THREADS:=8}"
    echo "LDFLAGS_EXTRA         ${LDFLAGS_EXTRA}"
    echo "CMAKEFLAGS_EXTRA      ${CMAKEFLAGS_EXTRA}"
    # result
    echo "LIBKLAPACK_FULL_SO    ${LIBKLAPACK_FULL_SO:=./libklapack_full.so}"
    export CMAKE_BUILD_TYPE CTEST_PARALLEL_LEVEL OMP_NUM_THREADS
    test -x ${LIBKLAPACK_SO} || DIE "invalid LIBKLAPACK_SO"
    test -x ${LIBKBLAS_SO} || DIE "invalid LIBKBLAS_SO"
    test -r ${LAPACK_SRC_DIR}/SRC/dgetrf.f || DIE "invalid LAPACK_SRC_DIR
    Download hint:
        git clone https://github.com/Reference-LAPACK/lapack ${LAPACK_SRC_DIR}
    "
    #-------------------------------------------------------------------------------
    kmlver=$(strings ${LIBKLAPACK_SO/klapack.so*/kservice.so} | grep -o 'VERSION.*COMPILER.*')
    INFORM "Check if compilers are compatible with KML '${kmlver}'"
    function check_compiler {
        local name=$1 parlor=$2
        case `${!name} --version 2>/dev/null` in
        *${parlor}*) echo "  Using ${name}=${!name}" ;;
        '') DIE "Missing compiler ${name}=${!name}" ;;
        *) DIE "Wrong compiler ${name}=${!name}" ;;
        esac
    }
    case ${kmlver} in
    *COMPILER:GNU*)
        export CC=${CC:-gcc} FC=${FC:-gfortran}
        check_compiler CC 'gcc'
        check_compiler FC 'GNU Fortran'
        ;;
    *COMPILER:Clang*)
        export CC=${CC:-clang} FC=${FC:-flang}
        check_compiler CC 'clang'
        check_compiler FC '?lang'
        ;;
    *)
        DIE "Unknown KML version ${kmlver}"
        ;;
    esac
    #-------------------------------------------------------------------------------
    INFORM "Configure BUILD_DIR for building STATIC liblapack.a and liblapacke.a"
    cmake_flags=(
        -DBLAS_LIBRARIES=NO
        -DBLASLIB="${LIBKBLAS_SO}"
        -DBUILD_DEPRECATED=ON
        -DBUILD_SHARED_LIBS=OFF
        -DBUILD_TESTING=OFF
        -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
        -DCMAKE_INSTALL_PREFIX=/dev/null
        -DCMAKE_POSITION_INDEPENDENT_CODE=ON
        -DCMAKE_RULE_MESSAGES=OFF
        -DLAPACKE=ON
        -DUSE_OPTIMIZED_BLAS=ON
        ${CMAKEFLAGS_EXTRA}
    )
    ( set -x ; mkdir -p ${BUILD_DIR} )
    ( set -x ; cd ${BUILD_DIR} ; cmake ${LAPACK_SRC_DIR} "${cmake_flags[@]}" )
    #-------------------------------------------------------------------------------
    INFORM "Build adapted liblapack.a, and liblapacke.a"
    rm ${BUILD_DIR}/lib/liblapack.a || true
    rm ${BUILD_DIR}/lib/liblapacke.a || true
    ( set -x ; cd ${BUILD_DIR} ; cmake --build . --parallel || cmake --build . --parallel 1 -v )
    ar d ${BUILD_DIR}/lib/liblapack.a xerbla.f.o
    # ------------------------------------------------------------------------------
    INFORM "Get symbols defined BOTH in KLAPACK and in Reference LAPACK"
    nm -g ${BUILD_DIR}/lib/liblapack.a | grep -oP ' T \K\w+(?=_$)' | sort | uniq > netlib.sym
    nm -g ${LIBKLAPACK_SO/klapack.so*/klapack.a} | grep -oP ' T \K\w+(?=_$)' | sort | uniq > klapack.sym
    comm -12 klapack.sym netlib.sym > comm.sym
    # ------------------------------------------------------------------------------
    INFORM "Extract relevant modules and update symbol names"
    ( set -x ; mkdir -p ${BUILD_DIR}/mods )
    while read sym; do
        (
            cd ${BUILD_DIR}/mods
            tloc=$(nm -gA --defined-only ${BUILD_DIR}/lib/liblapack.a | grep " T ${sym}_\$")
            if [[ -n "${tloc}" ]]; then
                libmod=${tloc%:*}
                mod=${libmod#*:}
                ( set -x ; ar x ${BUILD_DIR}/lib/liblapack.a ${mod} )
                ( set -x ; objcopy --redefine-sym ${sym}_=${sym}_netlib_ ${mod} )
            fi
        ) &
    done < comm.sym
    wait
    ar d ${BUILD_DIR}/lib/liblapack.a $(cd ${BUILD_DIR}/mods ; ls *.o)
    ( cd ${BUILD_DIR}/mods ; ar ru ${BUILD_DIR}/lib/liblapack.a *.o )
    ( cd ${BUILD_DIR}/mods ; rm *.o )
    #-------------------------------------------------------------------------------
    INFORM "Amend libkservice.a before building libklapack_full.so"
    libkservice_fixed_a=${BUILD_DIR}/lib/libkservice_fixed.a
    ( set -x ; cp -p ${LIBKLAPACK_SO/klapack.so*/kservice.a} ${libkservice_fixed_a})
    ( set -x ; ar d ${libkservice_fixed_a} timer.c.o || true )
    #-------------------------------------------------------------------------------
    INFORM "Create libklapack_full.so"
    ( set -x ; mkdir -p $(dirname ${LIBKLAPACK_FULL_SO}))
    ldflags=(
        -Wl,--whole-archive
        -Wl,--start-group
        ${LIBKLAPACK_SO/klapack.so*/klapack.a}
        ${BUILD_DIR}/lib/liblapack.a
        ${BUILD_DIR}/lib/liblapacke.a
        ${libkservice_fixed_a}
        -Wl,--end-group
        -Wl,--no-whole-archive
        ${LDFLAGS_EXTRA}
    )
    case ${kmlver} in
    *COMPILER:GNU*)
            ( set -x ; ${FC} "${ldflags[@]}" -lstdc++ -shared -o ${LIBKLAPACK_FULL_SO} )
            ;;
    *COMPILER:Clang*)
            ( set -x ; ${FC} "${ldflags[@]}" -lc++ -shared -o ${LIBKLAPACK_FULL_SO} )
            ;;
    esac
    #-------------------------------------------------------------------------------
    if [[ "$1" == "test" ]]; then
        INFORM "Run tests with libklapack_full.so"
        function tests {
            local tmp_dir=$1 lapack_libs=$2
            cmake_flags=(
                -DBUILD_TESTING=ON
                -DUSE_OPTIMIZED_BLAS=ON
                -DUSE_OPTIMIZED_LAPACK=ON
                -DBLAS_LIBRARIES="${LIBKBLAS_SO}"
                -DLAPACK_LIBRARIES="${lapack_libs}"
                -DCMAKE_RULE_MESSAGES=OFF
                -DLAPACKE=ON
            )
            mkdir -p ${tmp_dir}
            ( set -x ; cd ${tmp_dir} ; cmake ${LAPACK_SRC_DIR} "${cmake_flags[@]}" )
            ( set -x ; cd ${tmp_dir} ; cmake --build . --parallel || cmake --build . --parallel 1 -v )
            ( set -x ; cd ${tmp_dir} ; ctest --output-on-failure )
            echo "FINISHED LAPACK TESTS IN ${tmp_dir}"
        }
        tests ${BUILD_DIR}-tests "${LIBKLAPACK_FULL_SO};${LIBKBLAS_SO};-fopenmp"
    fi
    # Report build results ---------------------------------------------------------
    cat <<EOF
    --------------------------------------------------------------------------------
    FOR THIS KLAPACK LIBRARY (${kmlver}):
    $(ls -lU ${LIBKLAPACK_SO} ${LIBKLAPACK_SO/klapack.so*/klapack.a})
    WE HAVE BUILT FULL LAPACK+LAPACKE LIBRARY:
    $(ls -lU ${LIBKLAPACK_FULL_SO})
    USE THESE HEADER FILES:
    $(ls -lU ${BUILD_DIR}/include/*.h)
    --------------------------------------------------------------------------------
    EOF
  3. 执行完成后会在目录下会生成libklapack_full.so,可以单独链接此so得到LAPACK-3.12.0的全部接口功能。

    此时仍然需要单独链接KML_BLAS库以及libgfortran等系统库。

安装后验证

使用时,假设环境变量KML_LAPACK_ROOT为libklapack.*所在目录,ADAPT_ROOT为适配后Netlib LAPACK库所在目录。用户应用可以选择使用动态链接库或静态链接库。编译应用源代码时需要链接到KML_LAPACK、Netlib LAPACK、Netlib BLAS和gfortran库并开启OpenMP支持。

  • 场景一:协同KML_BLAS场景(高性能)
    假设KML_BLAS已构建的库(libkblas.a和libkblas.so)位于KML_BLAS_ROOT中,为获得最高性能请使用KML_BLAS单线程版本。当使用KML_BLAS时,仍然需要上一节最后获得Netlib LAPACK适配的liblapack_adapt.a,但不再需要Netlib LAPACK中的libblas.a。

    KML_LAPACK多线程调用KML_BLAS,因此不可以使用nolocking版本的KML_BLAS,推荐使用omp版本,即/usr/local/kml/lib/neon/kblas/omp/libkblas.so。

    • 使用动态链接库

      此场景下由于适配的Netlib LAPACK只有静态库liblapack_adapt.a,因此总是静态链接到此库。不再需要链接Netlib LAPACK的libblas.a。

      gcc app.c -o app -fopenmp -I $KML_LAPACK_ROOT/include -L /usr/local/kml/lib/neon -lklapack -L $ADAPT_ROOT -l:liblapack_adapt.a -L $KML_BLAS_ROOT -lkblas -lgfortran -lm -lkservice

      运行时需能找到KML_LAPACK所需的这些动态链接库,或者将/usr/local/kml/lib/neon/和$KML_BLAS_ROOT加入LD_LIBRARY_PATH。

      export LD_LIBRARY_PATH=/usr/local/kml/lib/neon/:$KML_BLAS_ROOT:$LD_LIBRARY_PATH
    • 使用静态链接库

      此场景不再需要链接Netlib LAPACK的libblas.a。

      gcc app.c -o app -fopenmp -I $KML_LAPACK_ROOT/include/kml-0.3.0 -L /usr/local/kml/lib/neon -l:libklapack.a -L $ADAPT_ROOT -l:liblapack_adapt.a -L $KML_BLAS_ROOT -l:libkblas.a -l:libkservice.a -l:libgfortran.a -lm

      其中app.c为示例代码,请参见“KML_LAPACK库函数说明>矩阵分解函数”中对应函数的代码示例。

  • 场景二:无KML_BLAS场景(依赖Netlib LAPACK中自带的BLAS,性能较低)
    • 使用动态链接库
      gcc app.c -o app -fopenmp -I $KML_LAPACK_ROOT/include/ -L /usr/local/kml/lib/neon -lklapack -L $ADAPT_ROOT -l:liblapack_adapt.a -lblas -lgfortran -lm -lkservice

      运行时需能找到KML_LAPACK所需的这些动态链接库,或者将/usr/local/kml/lib和$ADAPT_ROOT加入LD_LIBRARY_PATH。

      export LD_LIBRARY_PATH=/usr/local/kml/lib/neon:$ADAPT_ROOT:$LD_LIBRARY_PATH
    • 使用静态链接库
      gcc app.c -o app -fopenmp -I $KML_LAPACK_ROOT/include/ -L  /usr/local/kml/lib/neon -l:libklapack.a -L $ADAPT_ROOT -l:liblapack_adapt.a -l:libblas.a -l:libkservice.a -l:libgfortran.a -lm