加速图像处理的神器: Intel ISPC编译器 (五) 迁移图像旋转算法 - ISPC单精度 从单核到多核 及最终性能提升结果

本文主要是介绍加速图像处理的神器: Intel ISPC编译器 (五) 迁移图像旋转算法 - ISPC单精度 从单核到多核 及最终性能提升结果,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

现在CPU的核心数越来越多,即使现在的移动平台也是动辄4核起。前面的代码都是用单线程来运行的,所以只用到了CPU的一个核心。接下来尝试一下使用ISPC多任务机制来利用CPU的多核加速。

 

ISPC代码从单核到多核的优化

在ISPC的开发手册里,最简单的多任务机制用到了2个关键字 launch和task

  • 在一个函数前面加关键字task,标识这个函数是任务函数,可以在其他代码里通过launch语句来启动。任务函数可以被同时启动多次,在函数里有个内建的变量taskIndex, 标识着当前任务是第几个任务。
task void foo_task()
{print("taskIndex = %\n", taskIndex);
}
  • launch用来启动任务,launch后面的数组[100]表示同时启动100个foo_task任务
launch[100] foo_task();
  • ISPC编译器默认不提供多任务管理库,也就是说对应launch任务的底层函数需要自己来实现,具体的说明可以参考开发手册的“Task Parallelism: Runtime Requirements”部分。好在ISPC的例程里自带了一套示例代码tasksys.cpp, 前面在cmake的配置文件里设置USE_COMMON_SETTINGS,项目就会自动编译链接这个tasksys.cpp。

 

 接下来把image_rotate_float_ispc()改成多任务版,先把输入图像分成多个小块,每个任务处理32像素高度的图像
块。

对应代码

#define M_PI_F 3.1415926535ftask void image_rotate_float_ispc_task(uniform const uint8 srcImg[], uniform uint8 dstImg[], uniform float center_x,uniform float center_y, uniform int iWidth, uniform int iHeight, uniform int span, uniform float skewDegree)
{//计算当前任务需要处理的图像块的起始y坐标和结束y坐标uniform int ystart = taskIndex * span;uniform int yend = min((taskIndex+1) * span, (unsigned int)iHeight);uniform float angle = (float)RotateDegree*M_PI_F / 180.0;uniform float alpha = cos(angle);uniform float beta = sin(angle);uniform float m[6];m[0] = alpha;m[1] = -beta;m[2] = (1.0 - alpha) * (float)center_x + beta * (float)center_y ;m[3] = beta;m[4] = alpha;m[5] = (1.0 - alpha) * (float)center_y - beta * (float)center_x;foreach (row = ystart ... yend, col = 0 ... iWidth)  {float x, y;int leftX, rightX, topY, bottomY;float w00, w01, w10, w11;float fxy;x = m[0] * (float)col + m[1] * (float)row + m[2];y = m[3] * (float)col + m[4] * (float)row + m[5];leftX = floor(x);topY = floor(y);rightX = leftX + 1.0;bottomY = topY + 1.0;w11 = abs(x - leftX)*abs(y - topY);w01 = abs(1.0 - (x - leftX))*abs(y - topY);w10 = abs(x - leftX)*abs(1 - (y - topY));w00 = abs(1.0 - (x - leftX))*abs(1.0 - (y - topY));if ((int)leftX >= 0 && (int)rightX < Width && (int)topY >= 0 && (int)bottomY < Height) {fxy = (float)srcImg[topY*Width+ leftX]*w00 + (float)srcImg[bottomY*Width+ leftX]*w01 +(float)srcImg[topY*Width+ rightX]*w10 + (float)srcImg[bottomY*Width+ rightX]*w11;fxy = round(fxy);if (fxy < 0)fxy = 0;if (fxy > 255)fxy = 255;dstImg[row*Width+ col] = (uint8)(fxy);}elsedstImg[row*Width + col] = 0;};
};export void myWarpAffine_float_ispc_mt(uniform const uint8 srcImg[], uniform uint8 dstImg[], uniform float center_x,uniform float center_y, uniform int iWidth, uniform int iHeight, uniform float skewDegree)
{//任务分块,定义每个任务处理32像素高的图像块uniform int span = 32;//启动任务launch[iHeight/span] image_rotate_float_ispc_task(srcImg, dstImg, center_x, center_y, iWidth, iHeight, span, skewDegree);
};

 

运行一下多任务版本,我这个4核8线程的笔记本上耗时: 230ms

ISPC多核对单核算法的效率对比为

781ms/230ms=3.40X

也基本接近了4核4倍的理论值

 

最后的收官优化

在最后阅读ISPC开发手册的时候,发现了一个clamp函数

The clamp() functions clamp the provided value to the given range. (Their implementations are based on min() and max() and are thus quite efficient.)float clamp(float v, float low, float high)

这不就是做我的代码里的把最终算出的像素值卡到[0,255]之间的功能么,赶快替换一下

				fxy = round(fxy);
#if 0if (fxy < 0)fxy = 0;if (fxy > 255)fxy = 255;
#elsefxy = clamp(fxy,0,255);
#endif

最后多核的运行时间: 211ms  又快了一点 :)

 

最终的性能提升总结

代码优化到这里,已经利用了SIMD和多核的硬件优势,大的优化可能基本已经没有了。如果要进一步的优化,就需要从内存和缓存的读取写入的利用率来重新调整代码架构了。这就属于终极优化部分了,对于我这个测试程序就没有意义了。

 

现在对比一下原始C代码和ISPC多核版本的性能提升

4294ms/211ms = 20.35X

 

对应的是并不多的改动时间,回报是巨大的,ISPC真乃神器 强烈推荐:)

 

最后放上ISPC的几个链接

ISPC的主页   这里是总入口,可以找到各种发行包,开发文档以及性能测试等各类信息

ISPC的Github ISPC编译器是完全开源的,有兴趣开发者的可以加上对自家硬件的支持

 

这篇关于加速图像处理的神器: Intel ISPC编译器 (五) 迁移图像旋转算法 - ISPC单精度 从单核到多核 及最终性能提升结果的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/300997

相关文章

mysql线上查询之前要性能调优的技巧及示例

《mysql线上查询之前要性能调优的技巧及示例》文章介绍了查询优化的几种方法,包括使用索引、避免不必要的列和行、有效的JOIN策略、子查询和派生表的优化、查询提示和优化器提示等,这些方法可以帮助提高数... 目录避免不必要的列和行使用有效的JOIN策略使用子查询和派生表时要小心使用查询提示和优化器提示其他常

golang字符串匹配算法解读

《golang字符串匹配算法解读》文章介绍了字符串匹配算法的原理,特别是Knuth-Morris-Pratt(KMP)算法,该算法通过构建模式串的前缀表来减少匹配时的不必要的字符比较,从而提高效率,在... 目录简介KMP实现代码总结简介字符串匹配算法主要用于在一个较长的文本串中查找一个较短的字符串(称为

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

在不同系统间迁移Python程序的方法与教程

《在不同系统间迁移Python程序的方法与教程》本文介绍了几种将Windows上编写的Python程序迁移到Linux服务器上的方法,包括使用虚拟环境和依赖冻结、容器化技术(如Docker)、使用An... 目录使用虚拟环境和依赖冻结1. 创建虚拟环境2. 冻结依赖使用容器化技术(如 docker)1. 创

Tomcat高效部署与性能优化方式

《Tomcat高效部署与性能优化方式》本文介绍了如何高效部署Tomcat并进行性能优化,以确保Web应用的稳定运行和高效响应,高效部署包括环境准备、安装Tomcat、配置Tomcat、部署应用和启动T... 目录Tomcat高效部署与性能优化一、引言二、Tomcat高效部署三、Tomcat性能优化总结Tom

SQL Server数据库迁移到MySQL的完整指南

《SQLServer数据库迁移到MySQL的完整指南》在企业应用开发中,数据库迁移是一个常见的需求,随着业务的发展,企业可能会从SQLServer转向MySQL,原因可能是成本、性能、跨平台兼容性等... 目录一、迁移前的准备工作1.1 确定迁移范围1.2 评估兼容性1.3 备份数据二、迁移工具的选择2.1

css实现图片旋转功能

《css实现图片旋转功能》:本文主要介绍了四种CSS变换效果:图片旋转90度、水平翻转、垂直翻转,并附带了相应的代码示例,详细内容请阅读本文,希望能对你有所帮助... 一 css实现图片旋转90度.icon{ -moz-transform:rotate(-90deg); -webkit-transfo

Linux编译器--gcc/g++使用方式

《Linux编译器--gcc/g++使用方式》文章主要介绍了C/C++程序的编译过程,包括预编译、编译、汇编和链接四个阶段,并详细解释了每个阶段的作用和具体操作,同时,还介绍了调试和发布版本的概念... 目录一、预编译指令1.1预处理功能1.2指令1.3问题扩展二、编译(生成汇编)三、汇编(生成二进制机器语