算法优化

第一章 引入基础

基本思路 优化循环,降低计算量

  • 降低循环层数 – x86上有明显效果, arm上未见明显效果
  • 去除if语句 --有明显效果
1.x86上优化
//原代码
	int i = 0, j = 0;
	int P[25] = {0};
	int y_add = queryYAdd(fmt);
	uint8_t *myGrad = new uint8_t[w_algn*h*2];
    uint8_t *myRawY = nullptr;
	uint16_t *raw_addr = (uint16_t *)y_addr;
    smd_sub = 0;
	if(y_addr == nullptr)
	{
		return BAD_VALUE;
	}
	if( fmt == BAYER_RAW)
	{
				myRawY = new uint8_t[w_algn*h*2];
			for (i = start_Dpoint.x; i < start_Dpoint.x + x_width - 1; i++)
			{
				for ( j = start_Dpoint.y; j < start_Dpoint.y + y_height - 1; j++)
				{
				    if(1){
					    int idx = (j * w_algn + i);
					    //int idx_buttom = idx + w_algn;
					    //int idx_right = idx + 1;
					    int value_idx= raw_addr[idx] >>4;
					    int value_idx_buttom= raw_addr[idx + w_algn] >>4;
					    int value_idx_right = raw_addr[idx + 1] >>4;
					    int diff1 = abs(value_idx - value_idx_buttom);
					    int diff2 = abs(value_idx - value_idx_right);
    					if( value_idx < 10 || value_idx_buttom < 10 || value_idx_right < 10)
    					{
    						continue;
    					}
    					if( diff1/5 == 25 || diff2/5 == 25 ){
    						raw_addr[idx] = 0;
    					}
                        #endif
    					smd_sub += diff1 * diff2;
    					P[int(diff1/10)]++;
    					P[int(diff2/10)]++;
    					myGrad[idx] = (int)(diff1 * diff2)/(255.0)
    					//Rwa Y
    					myRawY[idx] = raw_addr[idx] >>4<<2;
                    }
				}
			}
			printf("smd_sub00 %d\n", (int)smd_sub);
			for(int  k =0 ; k< 25; k++)
			{
				printf("%d ", P[k]);
			}
			printf("\n");

1000次 原始数据 27s

第一轮:()
1.去掉core函数中的alloc ->19s
2.去掉统计,去掉if ->16s
3.去掉 中间值 diff1*diff2 ->13s
4.去掉循环嵌套,两层变一层 ->7s
5.加if 屏蔽瑕疵点 ->10s
6.两个abs去掉一个->无影响
7.去掉if -->8.4
8.减为一句->7.18s
9.去掉for中乘法->7.08
10.将smd 结果值double修改为int ->6.7s
经过第一轮,core中只有一个for循环,只有一行代码

//优化后
	if( fmt == BAYER_RAW)
	{
            int max_size = w_algn * (y_height-1);
			for (i = 0; i < max_size; i++)
			{
					int_smd_sub += abs((raw_addr[i] - raw_addr[i + w_algn]) * (raw_addr[i] - raw_addr[i + 1]));
			}
	}

第二轮:
1.未进行
第三轮:
1.未进行

2. arm上的优化

384*384 raw 300次 原始数据0.32018s , 32位程序
camera打开时候原始数据是7-8ms
在x86的基础上
第一轮:
1.改为128位一次 ->0.2962s
2.去掉 volatile ->0.1806031s
3.去掉 register->0.185144s
.去掉 extern c 变差 ->0.186s
4.改为4位 ->0.07065s (32位程序最佳)
改为32位 ->0.05836s(64位程序最佳)
改为48位(qcom8953最佳)
5.另开循环,增加去行尾部,瑕疵点 ->0.071409s
6.去掉log ->0.065346s
7.去掉for中的两个++ ->0.062144s

总结:
优化的原则. 降低循环层数>降低循环次数>=降低单次循环的运算量
1.尽量使用单次循环
2.去除循环内if语句
3.减少循环内中间变量数量
4.循环内不使用double类型。
5.循环内一次处理多位数据,降低循环次数
细节:
1.指针访问不应该大于8 (pointer+8 ) --不要出现(pointer+n ) ,n>=8
2.for(;不应有计算;)
3.不应该有log,android设备一次log的时间为20us

x86架构:
1.使用register变量
2.减少循环次数,增加单次计算量,能指数减少处理时间

第二章 Arm汇编及NEON优化

需要学习一下知识:

  • Arm架构32和64位寄存器
  • Arm汇编指令集 Arm官网
  • ddd
  • 熟知每一条NEON指令集,具体能做什么–这个是关键

总结:
没有减少指令数量很难优化

1.经典指令

byte5[1] & 0x3) << 8 会被解释成 UBFX R8, R4, #8, #2
UBFX
UBFX Rd(目标), Rn(源), #lsb(起始位0-31), #width(提取宽度)

实例: 图像 大小为 w * h * 5/4的图像,转为w*h图像
原始存储:

R1低8R2低6+R1高2R3低4+R2高4R4低2+R3高6R4高8

转为

R1高8R2高8R3高8R4高8

核心思路及代码:
由于没有5个通道的指令,五个一组的数据不太好处理。
每次加载 8*8*5 Bytes,用neon处理器处理为 8*8*4

  	   uint8x8x4_t byte_8x4 = vld4_u8(lineBuf);//加载8*4个Byte
  	   uint8x8_t byte5 = vld1_u8(lineBuf+32);	//加载8*1个Byte
  	   ...8*5的数据重新映射到4通道上,体力活
  	   //流处理器,一次性处理 8*4个Byte像素
  	   //vshr_n_u8 右移动取高位
  	   //vshr_n_u8 第二个操作数左移取低位并和第一个操作数按位或。
  	   byte_dest_8x4_final.val[0] = vsli_n_u8( vshr_n_u8( byte_dest_8x4.val[0], 2), byte_dest_8x4.val[1], 6);
  	   byte_dest_8x4_final.val[1] = vsli_n_u8( vshr_n_u8( byte_dest_8x4.val[1], 4), byte_dest_8x4.val[2], 4);
  	   byte_dest_8x4_final.val[2] = vsli_n_u8( vshr_n_u8( byte_dest_8x4.val[2], 6), byte_dest_8x4.val[3], 2);
       lineBuf+=40;
       //asm ("PLD [%0, #4095]"::"r" (lineBuf));
       vst4_u8( pu2DestBuf, byte_dest_8x4_final); // vst4_u8 一次写入8*4个数据到addr

优化结果:2000*1000的数据,优化前C代码8000us,neon优化后4200ms左右。
理论上,处理时间可以降低为180us 6 (6个流处理指令 单次循环时间),需要汇编级的优化。暂时没有实现。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值