1. 程式人生 > >DLIB在嵌入式上編譯總結

DLIB在嵌入式上編譯總結

前言

在海思3536上移植DLIB庫,用arm-hisiv300-linux-g++編譯器。

DLIB編譯

在DLIB下建Build目錄,進入。編譯指令碼如下:

cmake .. -DCMAKE_CXX_COMPILER:FILEPATH=arm-hisiv300-linux-g++ -DCMAKE_C_COMPILER:FILEPATH=arm-hisiv300-linux-gcc -DCMAKE_BUILD_TYPE:STRING=RELEASE -DHISIV300=1 -DDLIB_USE_BLAS=1 -DDLIB_USE_LAPACK=1

-DDLIB_USE_BLAS=1:尋找OPENBLAS,詳細後面說明。

-DHISIV300=1:因為我在同一份程式碼裡面除了交叉編譯以外,還用VS2015編譯WINDOWS版本,便於除錯。HISIV300用來區分是否嵌入式交叉編譯,在根CMakeLists.txt裡的指令碼如下:

cmake_minimum_required(VERSION 2.8.12)
if (HISIV300)
    message("configure hisiv300")
    #add_compile_options(-mcpu=cortex-a7 -mfloat-abi=softfp  -mno-unaligned-access -fno-aggressive-loop-optimizations
) add_compile_options(-mcpu=cortex-a7 -mfloat-abi=softfp -mfpu=neon-vfpv4 -mno-unaligned-access -fno-aggressive-loop-optimizations) #add_compile_options(-mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4 -mno-unaligned-access -fno-aggressive-loop-optimizations) add_compile_options(-D_GLIBCXX_USE_C99
) endif() add_subdirectory(dlib)

也嘗試各種浮點編譯選項,最後用的這是效能最好的。

因為DLIB編譯需要C++11,HISIV300編譯器對C++11支援還不是很好,要修改如下:

  1. 加-D_GLIBCXX_USE_C99這個巨集解決std::to_string等函式找不到的問題。

  2. 新增如下宣告:

#ifndef _WIN32
#define DLIB_USE_BLAS
namespace std
{
    double round(double f);
    float erfc(float f);
}
#endif

這兩個介面宣告找不到,也試了TR1巨集,沒搞定,就直接聲明瞭。

  1. exception_ptr很多介面連結時找不到,只能自己實現

#ifdef LINUX
#include <exception>
namespace std
{
    namespace __exception_ptr
    {
        exception_ptr::exception_ptr()
            :_M_exception_object(0)
        {}
        exception_ptr::~exception_ptr()
        {}
        exception_ptr::exception_ptr(const exception_ptr& e)
            :_M_exception_object(e._M_exception_object)
        {}
        exception_ptr& exception_ptr::operator=(const exception_ptr& e)
        {
            _M_exception_object = e._M_exception_object;
            return *this;
        }
        void exception_ptr::swap(exception_ptr& e)
        {
            void* tmp = _M_exception_object;
            _M_exception_object = e._M_exception_object;
            e._M_exception_object = tmp;
        }
    }

    //__thread exception_ptr g_cur_e;
    exception_ptr current_exception()
    {
        return exception_ptr();
    }
    void rethrow_exception(exception_ptr e)
    {
        throw std::exception();
    }
}
#endif

openblas編譯

-DDLIB_USE_BLAS=1查詢OPENBLAS庫,用來優化矩陣執行。下面開始編譯OPENBLAS庫。

make TARGET=ARMV7 ARM_SOFTFP_ABI=1 HOSTCC=gcc CC=arm-hisiv300-linux-gcc NOFORTRAN=1

開啟OPENMP開關作用不是很大,OPENBLAS預設2個執行緒工作。如果改成4個性能會變的很差,不確定原因。
將編譯後的.a,改成libopenblas.a。修改DLIB查詢openblas庫的路徑。
在dlib/cmake_utils/cmake_find_blas.txt,做如下修改:

   set(extra_paths
        /usr/lib64
        /usr/lib64/atlas-sse3
        /usr/lib64/atlas-sse2
        /usr/lib64/atlas
        /usr/lib
        /usr/lib/atlas-sse3
        /usr/lib/atlas-sse2
        /usr/lib/atlas
        /usr/lib/openblas-base
        /opt/OpenBLAS/lib
        ~/code/dlib
        $ENV{OPENBLAS_HOME}/lib
        )

tcmalloc編譯

用來優化記憶體分配。

下載gperftools程式碼,先執行./autogen.sh,可能需要安裝autoreconf、libtool連個工具。

然後:

./configure CC=arm-hisiv300-linux-gcc CXX=arm-hisiv300-linux-g++ --host=arm-linux CFLAGS="-mcpu=cortex-a7 -mfloat-abi=softfp -mfpu=neon-vfpv4 -mno-unaligned-access -fno-aggressive-loop-optimizations" CXXFLAGS="-mcpu=cortex-a7 -mfloat-abi=softfp -mfpu=neon-vfpv4 -mno-unaligned-access -fno-aggressive-loop-optimizations" --disable-cpu-profiler --disable-heap-profiler --disable-heap-checker --disable-debugalloc --enable-minimal

生成後的.a為libtcmalloc_minimal.a,可以改成libtcmalloc.a。

生成可執行檔案時,在所有連結的.a的最後面加入“-ltcmalloc”。

總結

這一波優化,在3536上,450*600解析度的圖片,特徵提取用時170ms/張,而人臉檢測用時300ms/張。