zoukankan      html  css  js  c++  java
  • 用sse4.1指令集加速cvCeil( )函数

    C/C++标准库,math.h/cmath中,给出了ceil()函数的声明。

    在OpenCV中,看到了cvCeil()函数,它是用sse2加速的。cvCeil()比ceil()快吗?评测下来,g++-5.4(ubuntu16.04)和VS2017下,确实都是cvCeil()更快。

    其实现在我用的PC,avx2都有支持了,sse、avx系列是递增式支持的,用sse4.1来优化一下cvCeil(),可以更快,普适性应该也还不错的。

    #include <iostream>
    #include <cmath>
    #include <sstream>
    #include <chrono>
    
    //sse2
    #if defined _MSC_VER && defined _M_X64 || (defined __GNUC__ && defined __SSE2__&& !defined __APPLE__)
    #include <emmintrin.h>
    #endif
    
    //sse 4.1
    #include <smmintrin.h>
    
    
    //sse2 optimized
    inline int cvCeil(double value)
    {
    #if defined _MSC_VER && defined _M_X64 || (defined __GNUC__ && defined __SSE2__&& !defined __APPLE__)
        __m128d t = _mm_set_sd( value );
        int i = _mm_cvtsd_si32(t);
        return i + _mm_movemask_pd(_mm_cmplt_sd(_mm_cvtsi32_sd(t,i), t));
    #elif defined __GNUC__
        int i = (int)value;
        return i + (i < value);
    #else
        int i = cvRound(value);
        float diff = (float)(i - value);
        return i + (diff < 0);
    #endif
    }
    
    
    //sse4 optimized
    inline int myCeil(double value)
    {
    #if defined _MSC_VER && defined _M_X64 || (defined __GNUC__ && defined __SSE2__&& !defined __APPLE__)
    
        /*
        //这段实现,ubuntu上clang-8.0,运行结果正确,但是VS2017运行结果不对。。速度是25ms
        __m128d val = _mm_set_sd(value);
        __m128d dst;
        _mm_round_sd(dst, val, _MM_FROUND_CEIL);
        return _mm_cvtsd_si32(dst);
        */
    
        //这段实现,ubuntu clang-8.0和VS2017结果都正确,不过慢了一些,70ms左右
        __m128d val = _mm_set_sd(value);
        __m128d res = _mm_round_sd(val, val, _MM_FROUND_CEIL);
        return _mm_cvtsd_si32(res);
    
    #elif defined __GNUC__
        int i = (int)value;
        return i + (i < value);
    #else
        int i = cvRound(value);
        float diff = (float)(i - value);
        return i + (diff < 0);
    #endif
    }
    
    
    
    template<typename T, typename P>
    std::string toString(std::chrono::duration<T,P> dt)
    {
        std::ostringstream str;
        using namespace std::chrono;
        str << duration_cast<microseconds>(dt).count()*1e-3 << " ms";
        return str.str();
    }
    
    int main () {
        volatile double x = 34.234;
        volatile double y1, y2, y3;
        const int MAX_ITER=100000000;
        const auto t0 = std::chrono::steady_clock::now();
    
        for(int i=0; i<MAX_ITER; i++) {
            y1 = std::ceil(x);
        }
        const auto t1 = std::chrono::steady_clock::now();
    
        for(int i=0; i<MAX_ITER; i++) {
            y2 = cvCeil(x);
        }
        const auto t2 = std::chrono::steady_clock::now();
    
        for(int i=0; i<MAX_ITER; i++) {
            y3 = myCeil(x);
        }
        const auto t3 = std::chrono::steady_clock::now();
    
    
    
        std::cout << "std::ceil: " << toString(t1-t0) << "
    ";
        std::cout << "cvCeil   : " << toString(t2-t1) << "
    ";
        std::cout << "myCeil   : " << toString(t3-t2) << "
    ";
        std::cout << "y1=" << y1 << ", y2=" << y2 << ", y3=" << y3 << std::endl;
    
        return 0;
    }
    

    编译指令:

    clang++-8 main8.cpp -O3 -o a8 -std=c++11 -msse4
    

    运行输出:

    std::ceil: 30.347 ms
    cvCeil   : 106.99 ms
    myCeil   : 72.361 ms
    y1=35, y2=35, y3=35
    

    换g++-5.4试试看?

    g++ main8.cpp -O3 -o a8 -std=c++11 -msse4
    
    std::ceil: 153.051 ms
    cvCeil   : 122.439 ms
    myCeil   : 85.935 ms
    y1=35, y2=35, y3=35
    

    看来g++-5.4的libstdc++里ceil的性能,也不如cvCeil

    在VS2017 Release模式运行得到:

    std::ceil: 344.014 ms
    cvCeil   : 119.165 ms
    myCeil   : 94.527 ms
    y1=35, y2=35, y3=35
    

    MSVCRT加油鸭

    附带:CMakeLists.txt中,给VS添加SSE4.1支持:

    if(MSVC)
       target_compile_definitions(ocv_test INTERFACE /arch:SSE4.1)
    endif()
    target_link_libraries(ocv_test ${OpenCV_LIBS})
    

    refs:
    is cvCeil() faster than standard library?
    MSDN - _mm_round_sd

  • 相关阅读:
    字符串转输入流、输入流转字符串
    base64编码与解码
    PHP AES/ECB 128加密
    JQ下拉加载更多
    php记录代码执行时间
    PHP SOAP 提交XML
    AES 加密 PHP 和 JAVA 互通
    PHP RSA算法 HMAC-SHA1加密算法
    php SHA256Hex加密
    php UTF8 转字节数组,后使用 MD5 计算摘要
  • 原文地址:https://www.cnblogs.com/zjutzz/p/12565754.html
Copyright © 2011-2022 走看看