sunnyqd 发表于 2014-9-14 21:31:43

【学习笔记四】原创申精,欢乐的比较KEIL、IAR、CW数据拷贝

本帖最后由 sunnyqd 于 2014-9-14 21:55 编辑

终于搞好了IAR和CW平台的配置
KEIL编译器为ARMCC
IAR编译器为IAR C/C++ Compiler for ARM
CW编译器为GNU C Compiler
据说KDS也为GNU C Compiler,那这里就不列出KDS了
以上三个平台采用速度最大优化,禁止内联

这只是一个简短的比较,难免有疏漏之处,只供参考

比较的函数为默认的库函数里的memcpy()和如下的函数

void intmemcpy(int32_t* dest, const int32_t* src,const int32_t size)
{
int32_t i;
for(i=0;i<size;i++)
{
    dest = src;
}
}
void intmemcpy2(int32_t* dest, const int32_t* src,int32_t size)
{
while(size--)
{
    dest=src;
}
}
void intmemcpy3(int32_t* dest, const int32_t* src,uint32_t size)
{
while(size--)
{
    dest=src;
}
}
void intmemcpy4(int32_t* dest, const int32_t* src,const int32_t size)
{
int32_t i;
for(i=0;i<size;i++)
{
    *dest++ = *src++;
}
}
void charmemcpy(char* dest, const char* src, const int32_t size)
{
int32_t i;
for(i=0;i<size;i++)
{
    dest = src;
}
}
void duffcpy(uint32_t* dest, const uint32_t* src, const uint32_t size)
{
uint32_t n = (size + 7u) >>3;
switch (size % 8)
{
      case 0:    do { *dest++ = *src++;
      case 7:   *dest++ = *src++;
      case 6:   *dest++ = *src++;
      case 5:   *dest++ = *src++;
      case 4:   *dest++ = *src++;
      case 3:   *dest++ = *src++;
      case 2:   *dest++ = *src++;
      case 1:   *dest++ = *src++;
      } while (--n > 0);
}
}
void duffcpy2(uint32_t* dest, const uint32_t* src, const uint32_t size)
{
uint32_t n = (size + 7u) >>3;
uint32_t i = 0;
switch (size % 8)
{
      case 0:    do { *dest++ = *src++;
      case 7:   *dest++ = *src++;
      case 6:   *dest++ = *src++;
      case 5:   *dest++ = *src++;
      case 4:   *dest++ = *src++;
      case 3:   *dest++ = *src++;
      case 2:   *dest++ = *src++;
      case 1:   *dest++ = *src++;
      } while (++i < n);
}
}
测试数据为
int32_t Buf0;\\放置在0x20000800;
int32_t Buf1;\\放置在0x20000A00;
int32_t Buf2;\\放置在0x1FFFFD00;
const int32_t Buf3;\\放置在0xF410;

平台配置为:
KEIL:
IAR:
CW:

这里插上一句,虽然选择了CW里的do not inline,但是编译后还是被inline,无奈,只好将上述函数放到另一个文件里才解决

以下为测试结果
KEIL:
IAR:
CW:

很有意思的结果,KEIL和IAR的速度分布比较类似,自带库memcpy的效率最高,其中IAR的memcpy最快为356个时钟周期
但是CW的结果很难令人理解自带memcpy速度最慢,而charmemcpy函数居然比intmemcpy函数快,也就是分单字节拷贝比用int拷贝的速度快,很奇怪
下面是部分分析

KEIL默认的memcpy为

IAR默认的memcpy为

按结果来,IAR更快一点

CW默认的memcpy速度慢的原因可能是与它的使用的库有关,这个memcpy默认使用了一个.c文件里的内容,反汇编为


难怪CW你这么慢呢。。。。我尝试了宏_EMBEDDED_WARRIOR_MEMFUNCS,但是看反汇编的结果不起作用,无语,对你失望了

CW的charmemcpy被编译成了好长的一段,如下



无语

继续,Keil下的intmemcpy为

IAR的intmemcpy为

可见IAR将循环展开了许多,这么卖力,难怪比Keil快

但是,对于duffcopy
Keil为

IAR为

CW为


KEIL和CW都比较老实的用了STM和LDM
IAR难怪这里你最慢了

按着三个平台搭建项目的体会是,Keil最简便,搭建的过程中没有任何问题,CW问题最多,需要手动更改好几个地方才可以
可能是与我Keil用的比较多也有一定的关系

按操作体验来说,Keil最便捷,CW最繁琐,IAR居中

按界面来看,IAR最简洁,但是比较难看,Keil居中,CW虽然在eclipse下面比较华丽,但是相对来说臃肿一些

所以对于Cortex我还是喜欢选择Keil,其次IAR,但不会选择使用CW,(KDS可能与CW类似,但是免费的,这是优势)

编辑原因:补充图片

浪里白条 发表于 2014-9-14 21:50:07

很有意思的测试,问一下,这个Ticks计数是如何实现的?

sunnyqd 发表于 2014-9-14 21:51:10

上面结果还可以发现一个有趣的现象
对于四个intmemcpy函数,均是intmemcpy和intmemcpy4的写法是最快的
对于
Keil:intmemcpy和intmemcpy4一样的速度
IAR:intmemcpy4较intmemcpy快
CW:intmemcpy较intmemcpy4快

其中IAR的intmemcpy4最快

sunnyqd 发表于 2014-9-14 21:53:32

浪里白条 发表于 2014-9-14 21:50
很有意思的测试,问一下,这个Ticks计数是如何实现的?

看我上一个帖子,http://www.amobbs.com/forum.php?mod=viewthread&tid=5596002&pid=7890315&page=1&extra=#pid7890315
使用systick,里面有说tick的获取方式是tick1-tick2-(tick0-tick1),其中(tick0-tick1)是调用systick函数时的开销

fengyunyu 发表于 2014-9-14 21:55:26

学习了。通过lz的分析,对汇编有了感性的认识。

浪里白条 发表于 2014-9-14 22:00:40

查了下汇编手册,没看懂这俩的区别



寻址方式不一样?

sunnyqd 发表于 2014-9-14 22:01:50

浪里白条 发表于 2014-9-14 22:00
查了下汇编手册,没看懂这俩的区别




一个可以一条指令加载多个寄存器,一个是只加载一个,M是multiple的意思

步之道 发表于 2014-9-14 22:05:49

确实keil虽然在界面上没有eclipse上好看,但是真的受不了eclipse的臃肿。可能跟我的电脑有关,难道要换了?

浪里白条 发表于 2014-9-14 22:06:31

CW和KEIL很傻,intmemcpy2和intmemcpy3中一个size-- 都不知道优化下。

浪里白条 发表于 2014-9-14 22:08:33

sunnyqd 发表于 2014-9-14 22:01
一个可以一条指令加载多个寄存器,一个是只加载一个,M是multiple的意思

字面意思能理解,为何会对速度造成影响呢?

loyal248 发表于 2014-9-14 22:09:01

又涨见识了!!!

sunnyqd 发表于 2014-9-14 22:09:41

浪里白条 发表于 2014-9-14 22:06
CW和KEIL很傻,intmemcpy2和intmemcpy3中一个size-- 都不知道优化下。

一个是uint,一个是int,keil里面可能考虑到输入是负数时的情况,分别处理

sunnyqd 发表于 2014-9-14 22:11:16

浪里白条 发表于 2014-9-14 22:08
字面意思能理解,为何会对速度造成影响呢?

这需要看详细的架构或指令手册了,LDM的特点是,加载完之后,可以自增

浪里白条 发表于 2014-9-14 22:13:39

sunnyqd 发表于 2014-9-14 22:11
这需要看详细的架构或指令手册了,LDM的特点是,加载完之后,可以自增

果然,看了下配图IAR有2个ADD

江南雨絮 发表于 2014-9-14 22:41:31

有意思!表示一直用Keil

ludikn 发表于 2014-9-15 07:40:52

lz有心人,这个比较研究很有意思。for, while, signed, unsigned这些的差异是对c语言的比较深入研究。

franki 发表于 2014-9-15 08:00:11

还是对GNU C Compiler 比较熟悉些 ,但是没用过CW 。看到了底层的汇编,头大

zhaotyue 发表于 2014-9-15 08:11:05

长见识了!         

ndust 发表于 2014-9-15 08:52:44

其实对照不同的编译器,观察语句和汇编,会发现有很大不同。如果经常分析C和汇编,就能写出优化程度高的C语言。当然得针对不同的编译器。
所以也建议不要经常更换编译器,毕竟用熟悉的环境能避免很多BUG.

zhengxg1990 发表于 2014-9-15 09:09:25

sunnyqd 发表于 2014-9-14 22:09
一个是uint,一个是int,keil里面可能考虑到输入是负数时的情况,分别处理

uint和int为什么要分别处理?不是都按32位来处理么,对MCU来说应该没什么区别呀

sunnyqd 发表于 2014-9-15 09:34:47

zhengxg1990 发表于 2014-9-15 09:09
uint和int为什么要分别处理?不是都按32位来处理么,对MCU来说应该没什么区别呀 ...

同样为0xFFFFFFF,一个是最大,一个是负1,与0判断的时候,明显不一样

zhengxg1990 发表于 2014-9-15 14:42:57

sunnyqd 发表于 2014-9-15 09:34
同样为0xFFFFFFF,一个是最大,一个是负1,与0判断的时候,明显不一样

不是比的数据拷贝么

DOER 发表于 2014-9-15 16:06:14

arm有专门的memcpy指令吧

xiayuan 发表于 2014-9-15 19:38:37

又学习了哇

guyue180 发表于 2014-9-15 21:12:14

长知识了。

32MCU 发表于 2014-9-16 09:19:50

楼主。辛苦了。

dgtg 发表于 2014-9-20 12:16:36

这个很有参考价值!!mark!!

chenyg 发表于 2014-9-20 12:39:27

很好!谢谢!

CrystalShell 发表于 2014-9-20 12:49:59

很好,mark

zsenbao 发表于 2014-9-20 12:50:50

欢乐的顶一下,学习了

qingzhou 发表于 2014-9-20 13:00:24

学习了。

markdif 发表于 2014-9-22 11:45:52

实战项目中,我用IAR较多。。。

zndz410 发表于 2014-9-23 10:12:02

楼主这一对比,很多用Keil的人找到了用它的理由了。{:titter:}

xjmlfm1 发表于 2014-9-23 11:21:55

楼主牛X,这个对比很详细,很有说服性。
考虑是不是要换到KEIl上去。CW太麻烦了。

cyberkyg 发表于 2014-9-26 16:17:54

mark         .
页: [1]
查看完整版本: 【学习笔记四】原创申精,欢乐的比较KEIL、IAR、CW数据拷贝