1 概述:
最近项目中性能比较吃紧,经过跟踪发现,memcpy操作的性能存在一定问题;于是,做了一些尝试去验证一些想法,记录一下;
环境: MDK530,Cortex M0芯片,主频80MHz左右,
2 优化手段:
在优化之前,我们要先确定基本的性能,于是写了一个简单的测试程序:
void my_memcpy(u8 *dest, u8* src, u16 len) {
u16 j;
for(j=0; j<len; j++) {
dest[j] = src[j];
}
}
main()
{
-------省略-------
for(i=0; i<10; i++)
{
non_os_enter_critical();
led2_times(1); //开始计时
my_memcpy(dst_buffer, src_buffer, 255);
led2_times(2); //结束计时
non_os_exit_critical();
osDelay(1);
}
-------省略-------
}
验证执行时间的方法,调用led2_times(1)在led2 IO上输出一个方波,led2_times(2)输出2个方波,通过逻辑分析仪或者示波器就可以测量这2个波形的间隔得出时间;就上述代码,测得时间为:
大约花了159us;
2.1 将代码执行放到RAM中
1, 将my_memcpy 便于到指定段中 "RAM_CODE"中,可以使用#pragma arm section code 的方式,也可以使用
在KEIL中可以通过__attribute__((at(address)))的方式将变量放到指定的位置。
通过__attribute__((section(“name ”)))的方式将变量或者函数放到指定的位置。
#pragma arm section code="RAM_CODE"
void my_memcpy(u8 *dest, u8* src, u16 len)
{
u16 j;
for(j=0; j<len; j++)
{
dest[j] = src[j];
}
}
#pragma arm section
2 在SCT文件中设置“RAM_CODE“段放到RAM的执行区域中;参考修改:
RW_IRAM1 0x20000200 0x00003F00 { ; RW data
*.o (RAM_CODE)
.ANY (+RW +ZI)
}
最后重新编译,测量执行时间缩减为63.9us, 效果比较明显,RAM的执行速度明显高于Flash中执行速度;
2.2 关于标准库memcpy
如下测试代码1,src_buffer,dst_buffer均采用4字节对齐;
main()
{
u8 src_buffer[0x104];
u8 dst_buffer[0x104];
-------省略-------
for(i=0; i<10; i++)
{
non_os_enter_critical();
led2_times(1); //开始计时
memcpy(dst_buffer, src_buffer, 255);
led2_times(2); //结束计时
non_os_exit_critical();
osDelay(1);
}
-------省略-------
}
测试结果为:
只需要46.74us
稍微修改一下测试代码2,不让dst_buffer进行4字节对齐
memcpy(dst_buffer+1, src_buffer, 255);
测试结果:
需要187.08us, 性能约等于单个字节逐个拷贝的情况;
因此得出结论:
使用库memcpy 情况下,
如果目标地址和源地址均采用4字节对齐,性能会有明显提升;
如果目标地址和源地址均不是4字节对齐,性能较差;
2.3 使用汇编实现memcpy
不叙述具体过程,直接说结果,效果比较好!