加速图像处理的神器: 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

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO