c++ - cvCeil() 比标准库快吗?

标签 c++ optimization c++-standard-library

我看到 OpenCV 实现 cvCeil功能:

CV_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
}

我对这个实现的第一部分很好奇,即 _mm_set_sd相关调用。它们会比 MSVCRT/libstdc++/libc++ 更快吗?为什么?

最佳答案

下面的一个简单基准告诉我 std::round在我启用 SSE4 的机器上工作速度提高了 3 倍以上,但在未启用 SSE4 时慢了大约 2 倍。

#include <cmath>
#include <chrono>
#include <sstream>
#include <iostream>
#include <opencv2/core/fast_math.hpp>

auto currentTime() { return std::chrono::steady_clock::now(); }

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 y;
    constexpr auto MAX_ITER=100'000'000;
    const auto t0=currentTime();
    for(int i=0;i<MAX_ITER;++i)
        y=std::ceil(x);
    const auto t1=currentTime();
    for(int i=0;i<MAX_ITER;++i)
        y=cvCeil(x);
    const auto t2=currentTime();
    std::cout << "std::ceil: " << toString(t1-t0) << "\n"
                 "cvCeil   : " << toString(t2-t1) << "\n";
}

我用 -O3 测试英特尔酷睿 i7-3930K 3.2 GHz 上的 GCC 8.3.0、glibc-2.27、Ubuntu 18.04.1 x86_64 上的选项。

使用 -msse4 编译时的输出:
std::ceil: 39.357 ms
cvCeil   : 143.224 ms

没有 -msse4 编译时的输出:
std::ceil: 274.945 ms
cvCeil   : 146.218 ms

很容易理解:SSE4.1引入了ROUNDSD指令,基本上是什么 std::round做。在此之前,编译器必须执行一些比较/条件移动技巧,并且还必须确保这些不会溢出。因此cvCeil版本,牺牲了 value>INT_MAX 的明确定义和 value<INT_MIN , 获得其明确定义的值的加速。对于其他人,它具有未定义的行为(或者,对于内在函数,只会给出错误的结果)。

关于c++ - cvCeil() 比标准库快吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60825541/

相关文章:

c++ - 默认的移动构造函数是否被认为是用户声明的?

c++ - 通过引用另一个类方法传递 vector 成员变量

c++ - 在 C++ 函数中,指针与索引数组

c++ - 如何优化我的截屏实用程序?

Python:将逗号分隔的字符串直接拆分为一个集合

c++ - 在 C++ 中从字符串中删除数字并保留下划线

c++ - <algorithm> 是否包含 <cmath>?

c++ - while 循环输出中的空内容

c++ - 为什么 SDL2 矩形和线条画不是像素完美的?

c++ - 如何一次包含所有的 C++ 标准库?