程序优化方法及步骤-20101203

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
7)使用软件流水技术
软件流水线技术用来对一个循环结构的指令进行调度安排,使之成为多重迭代循环并行执行。在编译代码时,可以选择编译器的-o2或-o3选项,则编译器将根据程序尽可能地安排软件流水线。
在DSP算法中存在大量的循环操作,因此充分地运用软件流水线方式,能极大地提高程序的运行速度。但使用软件流水线还有下面几点限制:
for (i = 0; i < 256; i++) RGB2YUV_UBVR[i] = (float)112 * (i<<8);
}
通过下面的计算公式计算Y、U、V值。
Y0=(RGB2YUV_YR[R0] +RGB2YUV_YG[G0]+RGB2YUV_YB[B0]+1048576)>>16;
U0=(-RGB2YUV_UR[R0] -RGB2YUV_UG[G0]+RGB2YUV_UBVR[B0]+8388608)>>16;
选择最佳方案。
根据实际编译的程序,选择合适的优化选项,进行源程序的优化。实际程序测试,结合使用-o3和-pm优化编译选项效率最高。
2)增加CACHE的使用
Cache即高速缓存,是位于CPU和片内存储器之间的规模小速度快的存储器。Cache的工作原理是保存CPU中最常用的数据。当Cache中保存着CPU要读写的数据时,CPU直接访问Cache。由于Cache的速度与CPU相当,CPU能在零等待状态下迅速地实现数据存取。只有在Cache中不含有CPU所需的数据时CPU才去访问片内存储器。因此Cache的有效利用对整个程序速度的提高有着举足轻重的作用。
根据对DM648 cache机制的理解,配置tcf文件,修改cache的配置为L1P cache 32k, L1D cache 32k, L2 cache 256k, IRAM 256k,具体配置方法如图示:
3)使用DSP超频技术
超频技术是将DSP处理速度提高,我们目前是将900M的芯片速度超频到1056M。该方法要慎重使用,一般超频不要超过300M(TI支持给的经验值,无具体测试)。具体超频方法为修改GEL文件中PLL设置为Set_Pll1( 32 );同时修改tcf文件配置修改DSP Speed In MHz为1056M。
2)使用关键字restrict
关键字restrict用来标明一个指针是指向该变量的唯一指针。这对循环中的软件流水极其有用,它告诉编译器,用restrict定义的指针,其所指向的存储空间不会发生混叠,从而能够很好的起到优化作用。如插值算法中定义
int Bayer2YUV422_OPT( unsigned char*restrictbayer0, int bayer_step,
● 循环结构不能包含代码调用,但可以包含内联函数。
● 循环计数器应该是递减的。
● 循环结构不能包含break,if语句不能嵌套,条件代码应当尽量的简单。
● 循环结构中不要包含改变循环计数器的代码。
● 循环体代码不能过长,因为寄存器(32个)的数量有限,应该分解为多个循环。
在软件流水线的运用上,应该尽量使复杂的循环分解成简单的小循环,以避免寄存器的数量不够;对于过于简单的循环,应该适当的展开,以增加代码数量,增加流水线中的迭代指令。目前我们将原来每次循环插值处理一行像素点展开为每次循环插值处理两行像素点。
V0 = (unsigned char)((2044*R8 - 1712*G8 - 333*B8)>>12) + 128;
这两种方法不一样的是第一种方法比较耗时的地方是数组读取操作,第二种方法比较耗时的地方是乘法运算。
理论上查表方法效率要高于定点运算方法,但实际测试比较第二种方法效率却高于第一种方法(即使第一种方法将数组定义在片内RAM)。这个测试结果可能存在争议(合理解释是数组的读取每次读取一个值时会将后面连续的128个字节值读取到cache中,如果下次读取的是上次读取的后128个字节以内的值则从cache中读取,速度会很快,但如果下次读取的是上次读取的后128个字节以外的值则需重新从数组中读取,速度会比较慢,目前我们转换运算是对数组进行非连续的读取,所以速度会较慢)
8)线性汇编优化
将算法中耗时的程序段用线性汇编代码改写实现。线性汇编是TI针对DSP开发做的介于C语言与汇编语言之间的开发语言,语言编程规范与汇编相似,用线性汇编语言编写完代码后再利用汇编优化器进行优化。汇编优化器的作用是让开发人员在不考虑C64X流水线结构和分配其内部寄存器的情况下,编写线形汇编语言程序,然后汇编优化器通过分配寄存器和循环优化将汇编语言程序转化为利用流水线方式的高速并行汇编程序,大大提高算法运行效率。汇编优化器从输入的线性汇编代码中,完成以下功能:
for (i = 0; i < 256; i++) RGB2YUV_UG[i] = (float)74.203 * (i<<8);
for (i = 0; i < 256; i++) RGB2YUV_VG[i] = (float)93.786 * (i<<8);
for (i = 0; i < 256; i++) RGB2YUV_VB[i] = (float)18.214 * (i<<8);
for (i = 0; i < 256; i++) RGB2YUV_YG[i] = (float)128.553 * (i<<8);
for (i = 0; i < 256; i++) RGB2YUV_YB[i] = (float)24.966 * (i<<8);
for (i = 0; i < 256; i++) RGB2YUV_UR[i] = (float)37.797 * (i<<8);
● -o:使能软件流水和其他优化方法
● -pm:使能程序级优化
● -mt:使能编译器假设程序中没有数据存储混淆,可进一步优化代码。
● -mg:使能分析(profile)优化代码
● -ms:确保不产生冗余循环,从而减小代码尺寸
● -mh:允许投机执行
● -mx:使能软件流水循环重试,基于循环次数对循环试用多个方案,以便
6)通过EDMA将接收到的网络数据包去除包头搬移到Bayer图像缓冲区。具体EDMA的配置及接口的实现参考《配置EDMA数据搬移及实现.doc》
2.图像处理算法优化,图像处理算法包括插值算法和色彩空间转换算法,算法优化按以下思路进行。
1)将插值算法和色彩空间转换算法合并,使插值算法直接输出YUV422图像,减少运算环节和循环次数。
5)使用乒乓buffer机制进行片内和片外数据之间的搬移。
6)将插值后的RGB888数据转换成YUV22数据有两种比较快速的方法。
A.使用查表方式进行色彩空间转换,程序初始化时产生一个RGB888转换为YUV422的查找表
static void InitYUVTable()
{
int i;
for (i = 0; i < 256; i++) RGB2YUV_YR[i] = (float)65.481 * (i<<8);
*pDst8++ = *pSrc8++;
}
}
else
{
pSrc8 = pSrc;
pDst8 = pDst;
while( len-- )
*pDst8++ = *pSrc8++;
}
*/
memcpy(pDst, pSrc, len);
}
5)修改ndk驱动,使网络每次能接收更大的数据包,详细修改方法参考《648网络驱动参数修改记录.doc》。
4)由于片内RAM与CPU工作在同一时钟频率,比片外RAM性能高得多。而且片内RAM数据访问的速度比片外RAM的速度快很多,所以将要处理的Bayer图像数据先搬移到片内RAM,再从片内读取图像数据进行处理,最后又从片内将处理后的数据搬移到片外。由于片内RAM空间有限,DM648 L2有256M的空间,一部分做为cache用,剩下做为片内RAM,所以每次只搬移4行Bayer数据到L2。这里的数据搬移同样可以利用EDMA技术实现快速搬移。
void mmCopy( void* pDst, void* pSrc, uint len )
{
/*
UINT32 *pSrc32, *pDst32;
UINT8 *pSrc8, *pDst8;
// Fast Case
if( !(((uint)pDst)&0x3) && !(((uint)pSrc)&0x3) )
程序优化方法及步骤
经过这段时间对GigE接口卡的开发,主要工作表现在程序的优化上,总结以下优化心得。一、程序优化的思路
1.首先考虑程序级优化,主要考虑程序整体设计上的优化。程序尽量采用多线程机制,充分利用CPU时间片;尽量减少数据的搬移操作。
2.对程序整体的优化
1)选用C编译器提供的优化选项
在编译器中提供了分为若干等级和种类的自动优化选项,如下:
V0=(RGB2YUV_UBVR[R0]-RGB2YUV_VG[G0]-RGB2YUV_VB[B0]+8388608)>>16;
B.直接将YUV422转换的浮点运算改为定点运算.
Y0 = (R8*1224+G8*2404+B8*467)>>12;
U0 = (unsigned char)((-692*R8 - 1356*G8+2044*B8)>>12) + 128;
1)更换ndk,采用最新版本的ndk 2.0,ndk2.0相对与ndk1.92有了更好的优化,而且支持巨帧,为后续修改ndk提高网络最大接收数据包提供基础。
2)使用recvnc()函数接收视频流,recvnc()函数相对于recv()函数接收减少了一次数据拷贝过程,recvnc()存储接收到的数据包buffer是事先分配好的buffer指针链表,每次接收指针往后移,详细参考《Network Developer’s Kit Programmer’s Reference Guide.pdf》。
DM648存储结构大致分为3个层次。依次是L1、L2和DDR2及外部存储。其中,L1分为L1P(程序储存器)和L1D(数据存储器),L2分为Cache和IRAM,Cache的容量可由用户定义,IRAM可有软件配置和指定。DDR2挂在L2的左侧。图中没有画出。具体结构如下图所示。
其中的L1、L2的详细结构如下图所示(具体参见《TMS320C64x DSP Two_Level Internal Memory Reference Guid.pdf》)。
3)采用阻塞模式接收,通过ndk创建socket默认为阻塞接收模式,若采用非阻塞模式接收,需通过网络读事件来判断网口有数据过来时才接收,无数据时不接收,增加了网络读事件判断过程,使接收效率下降。
4)修改ndk中os.lib源代码,将os.lib中的pmb.c文件中的mmCopy函数实现修改为memcpy(),重新编译(编译时用-o3 -pm)。
{
pSrc32 = pSrc;
pDst32 = pDst;
while( len > 3 )
{
*pDst32++ = *pSrc32++;
len -= 4;
}
if( len )
{
pSrc8 = (UINT8 *)pSrc32;
pDst8 = (UINT8 *)pDst32;
while( len-- )
unsigned char*restrictdst0, int width, int height, int code )
3)使用内联函数(intrinsics)
内联函数是C64X编译器提供的专门函数,它们与嵌入式的汇编指令是一一对应的,其目的是快速优化C源程序。在源程序中调用内联函数,与调用一般的函数相同,只不过内联函数名称前有下划线作特殊标识。当汇编指令功能不易采用C语言表达时,可采用内联函数表示。实际测试内联函数效率提高很少,具体使用参考《TMS320C6000 Optimizing Compiler》。
3.将程序分解为多个环节,分析每个环节的处理耗时情况,目前我们的程序主要有三个环节:网络接收视频流、图像算法处理、图像输出显示。
4.优先优化耗时比较大的环节,动态调整环节优化的侧重点,对各个子环节进行优化。网络接收视频流和图像算法处理是程序中最耗时的两个环节。
二、程序子环节优化
1.网络接收性能优化,由于接收GigE摄像机发送过来的高清视频流速度达到了538Mbps,虽然DM648具有千兆网口,但是网口接收频繁的产生中断,需要耗费大量的CPU。
相关文档
最新文档