用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) << "\n"; std::cout << "cvCeil : " << toString(t2-t1) << "\n"; std::cout << "myCeil : " << toString(t3-t2) << "\n"; 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
Greatness is never a given, it must be earned.
标签:
优化
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧